2012-09-01 5 views
0

나는 A<TInput, TOutput> 클래스의 특수화 클래스 인 B의 인스턴스를 가지고 있습니다. 클래스 B의 여러 변형이 있습니다. 다양한 입력 및 출력으로 구현 했으므로.제네릭을 사용하여 클래스에 객체 캐스트

TInputTOutput은 특정 입력 및 출력 클래스에 제약이 있으므로 IO이라고합시다.

Activator.CreateInstance을 사용하여 B을 인스턴스화하고 있지만 개체를 ​​반환하기 때문에 A<I, O>으로 캐스팅해야합니다. IO은 기본 클래스입니다 (이 경우 B<SpecialisationOfI, SpecalisationOfO>).

이 캐스트는 분명히 유효하지 않으므로 여기서 실패합니다.

의사 코드 :

abstract class I { } 
abstract class O { } 

abstract class A<TInput, TOutput> 
    where TInput : I 
    where TOutput : O 
{ 
    abstract TOutput Foo(TInput bar); 
} 

class Input : I { } 
class Output : O { } 

class B : A<Input, Output> { } 

A<I, O> instance = (A<I, O>)Activator.CreateInstance(typeOfB); // <-- fail 
instance.Foo(input); 

는이 일을 할 수 있습니까? 고맙습니다! 나는 주어진 해답을 기반으로

편집, 나는 크게 공분산에 따라 코드를 구조 조정하여이 문제를 해결했습니다

interface IA<TResult> { 
    TResult Foo(object input); 
} 

class A<TInput, TOutput> : IA<TOutput> 
    where TInput : I 
    where TOutput : O { 

    public TOutput Foo(object input) { 
    if (!(input is TInput)) { 
     throw new ArgumentException("input"); 
    } 

    return FooImpl(input as TInput); 
    } 

    protected abstract TOutput FooImpl(TInput input); 
} 

var instance = (IA<Output>) Activator.CreateInstance(type); 
instance.Foo(input); 

이 주셔서 감사합니다 : 나는 인터페이스에 A에서 Foo 이동 나와 함께 당신의 통찰력을 공유하십시오!

답변

3

이것은 인스턴스를 만드는 방법과 아무 관련이 없습니다. 이는 generic variance의 문제입니다. 당신이 기본적으로 수행하려는 것은이 유사합니다

List<object> objects = new List<string>(); 

그리고 그것은 유효하지의 이유는 코드의 다음 라인 (일반적으로) 될 수 있다는 것입니다 :

objects.Add(new object()); 

그 노력의 경우 인 목록에 추가하는 것은 나쁜 소식입니다.

interface class A<in TInput, out TOutput> 
    where TInput : I 
    where TOutput : O 
{ 
    abstract TOutput Foo(TInput bar); 
} 

여전히 아니다 : 당신이 인터페이스는 추상 클래스에서 변경, 당신은 C# 4를 사용하는 경우, 당신은 일반적인 공분산일반적인 contravariance를 사용할 수 있는지 지금

그래도 코드에 대해 작동하려면 입력 및 출력을 공변으로 사용하려고합니다.

Output Foo(Input bar); 

... 즉,이 유형 Input의 입력이 필요합니다 : 귀하의 B 클래스는이 같은 방법이있을 것이다. 당신이 어떤 구현 I의 작동 할 수 있어야한다 A<I, O>있어하지만 :

A<I, O> x = new B();    // Invalid, as discussed, to prevent... 
O output = x.Foo(new SomeOtherI()); // ... this line 
+0

알겠습니다! 그것은 의미가 있습니다.이제 'I'유형이 있다면 시나리오를 바꿀까요? – Leonard

+0

이 경우 나는 'I'의 전문화를 의미합니다. 이것은 아마도 복잡한 패턴으로 클래스를 서로 연관시키는 수단으로 주석을 사용하려는 시도입니다. – Leonard

+0

@ Zanathel : 죄송합니다. 이전에 이러한 의견을 놓쳤습니다. 'I'에 대한 차이가 필요 없다면, 더 간단 할 것입니다. 예 - 공분산은 일반적인 제약 ('TOutput : O')에 의해 도움을 받지만 반동은 그렇지 않습니다. –

관련 문제