2009-04-21 2 views
1

제네릭 및 새 멤버에 문제가 있습니다. ObjectA 유형의 객체에서 작동하는 제네릭 클래스를 작성했습니다. ObjectB는 ObjectA에서 파생되고 ObjectA의 멤버 중 일부를 숨 깁니다. ObjectB 유형을 generic 클래스의 type 매개 변수로 제공하면 ObjectB에 의해 숨겨진 멤버를 호출 할 때 ObjectB의 구현을 호출 할 것으로 예상됩니다. 그러나 CLR은 여전히 ​​숨겨진 멤버 (ObjectA의 구현)를 호출합니다. 이것은 제네릭 클래스에 ObjectB 유형을 명시 적으로 제공했기 때문에 비논리적 인 것처럼 보입니다. 이것은 제네릭 자체에 문제가 있습니까, 아니면 제가 잘못하고 있습니까?Generics : 숨겨진 멤버가 아닌 새 멤버에 액세스

편집 : 불행히도 ObjectA의 소스 코드에 액세스 할 수 없으며 재정의하려는 멤버가 가상이 아닙니다. ObjectA의 소스 코드에 액세스 할 수 있다면 구성원을 가상으로 만들 수 있지만 그렇게 할 수 없기 때문에 멤버를 "재정의"하는 유일한 방법은 "새"키워드를 사용하는 것입니다. 컴파일러에 의해 생성

class GenericClass<T> where T : ObjectA 
{ 
    public void DoWork(T item) 
    { 
     // When type parameter 'T' is ObjectB, should get ObjectB's implementation 
     item.Invoke(); 
    } 
} 

class ObjectA 
{ 
    public void Invoke() 
    { 
     // A's implementation... 
    } 
} 

class ObjectB : ObjectA 
{ 
    public new void Invoke() 
    { 
     // B's implementation... 
    } 
} 

static void Main() 
{ 
    GenericClass<ObjectB> genericClass = new GenericClass<ObjectB>(); 
    ObjectB objectB = new ObjectB(); 
    genericClass.DoWork(objectB); 
} 

답변

7

번호 호출은 컴파일 시간에 대해 알고있는 회원 에 있습니다. 그건 ObjectA에 의해 노출 된 회원들입니다.

가상/재정의 메서드를 사용하여 일반적인 상속을 사용하지 않는 이유는 무엇입니까? 여기

은 그런데, 물건의 같은 종류의 또 다른 예입니다 - 문자열에 대한 오버로드 == 연산자를 사용하지 않는, T 통화에서 string 경우에도 Foo에 :

using System; 

class Test 
{ 
    static bool Foo<T>(T first, T second) 
     where T : class 
    { 
     return first == second; 
    } 

    static void Main() 
    { 
     string x = "hello"; 
     string y = new string(x.ToCharArray()); 

     Console.WriteLine(Foo(x, y)); 
    } 
} 
+0

답장을 보내 주셔서 감사합니다. 가상/재정의 된 메서드를 사용하지만 System.Windows.Form을 상속하고 가상이 아닌 멤버에 대한 내 자신의 구현을 작성하려고합니다. –

+0

그러면 다음과 같이 액세스 할 수 없습니다. 당신이 "거의 가상으로"만들려고 노력하는 것처럼 들리지만 그렇게 작동하지 않습니다. –

+0

흠. 당신이 C++ 템플릿에 익숙하다면 이것은 다소 비 직관적이라고 나는 동의한다. C#은 템플릿 클래스의 컴파일을 분리하고 그 당시 ObjectA에 대해서만 알고 있습니다. 템플릿이 인스턴스화되면 인스턴스화 된 클래스는 ObjectB에 대한 추가 지식으로 다시 컴파일되지 않습니다. –

0

이 월 귀하의 질문에 대한 답변이 아니지만 귀하의 접근 방식에 대한 요점은 보이지 않습니다 (단순한 예를 볼 수 있기 때문에 그럴 수도 있습니다).

나는 다음과 같은 방법을 사용하는 것이 좋습니다 것입니다 :

class ObjectA 
{ 
    public virtual void Invoke() 
    { 
     // do some work 
    } 
} 

class ObjectB : ObjectA 
{ 
    public override void Invoke() 
    { 
     // do some other work 
    } 
} 

class GenericNotNeededClass 
{ 
    public void DoWork(ObjectA item) 
    { 
     item.Invoke(); 
    } 
} 


static void Main() 
{ 
    GenericNotNeededClass nonGenericClass = new GenericNotNeededClass(); 
    ObjectB objectB = new ObjectB(); 
    nonGenericClass.DoWork(objectB); 
} 

그 코드는 당신이 당신의 예제 코드를 기반으로, 찾고있는 것을하지 믿는 것입니다.

0

T를 일반용 ObjectA 유형으로 정의하십시오. Invoke()가 가상 일 경우 생각대로 작동하지만, 그렇지 않기 때문에 Generic이 ObjectA 구현을 호출하기 때문에 T가 정의되어 있습니다.

Invoke()의 ObjectB 구현을 가리키는 가상 메소드 테이블 항목이 없으므로 이것이 런타임에서 호출 할 수 있습니다. 가상 메소드 인 경우 VMT에 메소드 주소가 있으며 사용자가 생각한 것처럼 작동합니다.

관련 문제