2010-08-16 3 views
3

제네릭 클래스에서 정적 메서드 호출 : 그 제네릭 클래스에서일반 질문 ... 내가 제네릭 클래스가

public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new() 
{ 
} 

을, 나는 후손 인 LinkedItem 클래스에서 정적 기능으로 접근하고 싶습니다 MyItem 클래스의. (따라서 LinkedItem의 인스턴스를 만들지 않아도 됨).

가능합니까?

는 제네릭 형식 매개 변수 (C# 랭 사양 4.5 절)에 정적 메소드를 호출 할 수 없기 때문에 어떤이는 형식 매개 변수에서 직접 수 없습니다,

에릭

답변

2

을 주셔서 감사합니다.

정적 멤버 또는 중첩 형식을 식별하기 위해 멤버 액세스 (§7.5.4) 또는 형식 이름 (§3.8)에서 형식 매개 변수를 사용할 수 없습니다.

예 다른 사람들이 언급 한대로 리플렉션 트릭을 통해이를 달성 할 수 있습니다. 그러나 일반적으로 리플렉션을 사용하여 간단한 메소드 호출 시나리오를 해결하는 것은 나쁜 설계를 나타냅니다.

형식을 사용하여 정적 메서드를 캡슐화하는 팩터 리/대리자를 전달하는 것이 훨씬 더 좋은 디자인입니다.

class MyItem : MyItem { 
    static void TheFunction() { ... } 
} 

public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new() 
{ 
    public MyList(Action theStaticFunction) { 
    ... 
    } 
} 

new MyList<MyItem>(MyItem.TheFunction); 
+1

@Downvoter, 설명해 주시겠습니까? – JaredPar

+1

"이럴 수 없습니다"라고 말하면됩니다. 가능하다는 것과 그것을하는 방법을 보여주는 세 가지 답변이 있습니다. 귀하의 대답이 오해의 소지가 아니므로 아래 표결에 대해 어떻게 논합니까? –

+1

@ 존, 내 대답은 다른 답변에도 맞습니다. 리플렉션을 사용하면 제네릭 형식 매개 변수에 대해 메서드를 호출하지 않고 제네릭 형식 매개 변수의 형식에서 메서드를 호출합니다. 이 두 시나리오에는 상당한 차이가 있습니다. – JaredPar

0

이것은 불가능합니다. 문제의 정적 메서드가 포함되어야한다는 LinkedItem 매개 변수에 제약 조건을 선언 할 방법이 없습니다.

은 아마 당신이 얻을 것이다 가장 가까운입니다

public class ILinkedItemFactory<T> 
{ 
    void YourMethodGoesHere(); 
} 

public class MyList<LinkedItem, Factory> : List<LinkedItem> 
    where Factory : ILinkedItemFactory<LinkedItem> 
    where LinkedItem : MyItem, new() 
{ 
    public MyList(Factory factory) 
    { 
     factory.YourMethodGoesHere(); 
    } 
} 
+0

@Downvoter, 설명해 주시겠습니까? –

+1

+1 내가 왜 당신이 downvoted했는지, 또는 누구에 의해,하지만 난 다시 그것을 밖으로했습니다 :) 모르겠다. – Abel

2

그것은 반사를 통해 수행 할 수 있습니다. C#에는 정적 멤버에 대한 API 제약이 없기 때문에이를 수행 할 수있는 직접적인 방법은 없습니다.

내가 당신이있어 시나리오가 무엇인지 잘 모르겠지만, 대부분의 경우이 권장 솔루션 :

public class MyList<LinkedItem> : List<LinkedItem> 
             where LinkedItem : MyItem, new() 
{ 
    public int CallStaticMethod() 
    { 
     // Getting a static method named "M" from runtime type of LinkedItem 
     var methodInfo = typeof(LinkedItem) 
         .GetMethod("M", BindingFlags.Static | BindingFlags.Public); 

     // Invoking the static method, if the actual method will expect arguments 
     // they'll be passed in the array instead of empty array 
     return (int) methodInfo.Invoke(null, new object[0]); 
    } 

} 

public class MyItem 
{ 
} 

class MyItemImpl : MyItem 
{ 
    public MyItemImpl() 
    { 
    } 

    public static int M() 
    { 
     return 100; 
    } 
} 

그래서 아니며, 예를 들어 다음 코드는 100 인쇄됩니다 :

public void Test() 
{ 
    Console.WriteLine(new MyList<MyItemImpl>().CallStaticMethod()); 
} 
2

예, 가능하지만 MethodInfo를 typeof(T).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static)에서 가져 와서 Invoke을 호출하여 리플렉션을 사용해야합니다.

특히 MethodInfo 대신 ConstructorInfo에서 동일한 기술을 사용하여 생성자의 매개 변수를 사용하는 제네릭 팩터 리를 만드는 경우 매우 유용 할 수 있습니다. 그것은 아무 것도 사용하지 않아도됩니다. 특히, 컴파일 타임에 문제의 타입이 필요한 서명의 정적 메소드를 가지고 있으므로 타입 안전성이 없어지고 실행될 때까지는 그러한 에러가 잡히지 않을 것입니다.

0

기본적으로 이것은 불가능합니다. 그러나 호출 할 메서드의 이름을 알고 있고 모든 LinkedItem 형식에이 메서드가 포함되어 있다고 확신하는 경우 리플렉션을 사용하여 목표에 도달 할 수 있습니다.참고 : 일반 프로그래밍 작업을 위해 리플렉션을 해결하는 것보다 더 좋은 방법이 있습니다.

다음은 항상 DoSomething에 대해 true을 출력합니다. 항상 사용 가능한 정적 멤버를 호출합니다 (정적 메서드에서는 중요하지 않으므로 일반 형식 제약 조건을 제거했습니다).

public class MyList<LinkedItem> : List<LinkedItem> 
{ 
    public bool DoSomething() 
    { 
     Type t = typeof(LinkedItem); 
     object o = new Object(); 
     var result = t.InvokeMember("ReferenceEquals", 
      BindingFlags.InvokeMethod | 
      BindingFlags.Public | 
      BindingFlags.Static, 
      null, 
      null, new[] { o, o }); 

     return (result as bool?).Value; 
    } 
} 

// call it like this: 
MyList<string> ml = new MyList<string>(); 
bool value = ml.DoSomething(); // true 

추신 :이 입력하는 동안 한편, 다른 사람들이 같은 접근 방식 ;-)

0

을 제안하는 것 같지 직접 방법으로 당신은 아마 반사없이 명시되어 있지만 이것은 완전하게 가능하다. 기본 클래스에 비 정적 액세스 메서드를 구현하고 모든 상속 클래스에서 재정의되도록 할 수 있습니다. 제약 조건을 가지고 클래스에서 다음

public class MyItem 
{ 
    public static void DoSomeStaticStuff() { //DoSomeStaticStuff for MyItem } 
    public virtual void AccessSomeStaticStuff() { MyItem.DoSomeStaticStuff(); } 
} 

public class SomeItem : MyItem 
{ 
    public static void DoSomeStaticStuff() { //DoSomeStaticStuff for SomeItem } 
    public override void AccessSomeStaticStuff() { SomeItem.DoSomeStaticStuff(); } 
} 

여기서 T : MyItem 그냥 T.AccessSomeStaticStuff()를 호출 할 것이다;

+1

정적 메서드는 가상 수 없습니다,이 컴파일되지 않습니다. – Elisha

+0

@ Elisha : 죄송합니다. –

관련 문제