2014-06-18 2 views
1

이상한 반사 문제가 있습니다.리플렉션을 사용하여 T 유형의 인터페이스를 구현하는 클래스를 만들려면

인터페이스 IFooAttempt1을 구현하는 클래스 FooAttempt1을 참조하십시오.이 인터페이스는 IAnimal을 반환하는 속성이 있습니다. FooAttempt1의 경우 Dog을 반환합니다.

해당 프로그램에서 IFooAttempt1을 구현하는 클래스는 인스턴스화 된 다음 작업을 수행 한 후 자체 반영 유형과 키를 나중에 리플렉션을 사용하여 다시 수분 저장합니다. IFooAttempt1을 구현하는 많은 클래스가 있으며 아주 잘 작동하는 아키텍처입니다.

기본 프로세스는 Attempt1() 메서드에서 확인할 수 있습니다.

실제 클래스는 IFooAttempt1보다 약간 복잡하며 실수를하기 쉽습니다. 따라서 우리는 코드를 리팩터링하여 제네릭을 사용하여 이러한 클래스가 올바르게 구현되도록합니다.

일반 interface IFooAttempt2 <T> where T : IAnimal을 구현하는 FooAttempt2을 참조하십시오.

이 기능적으로 동일 동물의 속성은 이제

public Dog Animal 

보다는

IFooAttempt1
public IAnimal Animal 

IFooAttempt2로 정의되어 있지만 제네릭의 자동 문서화 기능은 우리가 오히려 더 구현하게 보장 복잡한 클래스는 매우 간단합니다.

Attempt2() 코드를 참조 할 때 문제가 발생합니다. 반사를 사용하는 경우 FooAttempt2 라인을

object o = constructor.Invoke(null); 
IFooAttempt2<IAnimal> foo2 = (IFooAttempt2<IAnimal>) o; 

표시 오류

An unhandled exception of type 'System.InvalidCastException' occurred in 
ConsoleApplication1.exe Additional information: Unable to cast object of 
type 'ConsoleApplication1.FooAttempt2' to type 'ConsoleApplication1.IFooAttempt2`1 
[ConsoleApplication1.IAnimal]'. 

나는 그 점을 이해할 수 있지만 방법이 반사를 사용 하는가를 다시? 직접 실행 창에

, 당신은

? o 
{ConsoleApplication1.FooAttempt2} 
Animal: {ConsoleApplication1.Dog} 

를 이동하는 경우가 있으므로 정확하게 반영하고있다. FooAttempt2IFooAttempt2<Dog>으로 정의 된 경우에도 (IFooAttempt2<IAnimal>)로 변환 할 수 없습니다. 여기서 DogIAnimal입니다.

내 즉각적인 생각이

Type type = assembly.GetType(className, false, true).MakeGenericType(new[] { typeof(IAnimal) }); 

을하려고했지만 그것은 컴파일되지 않습니다. 분명히 컴파일러는 싫어한다. typeof(interface)

이 단계에서 나는 완전히 붙어있다.

감사합니다.

public interface IFooAttempt2<out T> 
    where T : IAnimal 
{ 
    T Animal 
    { 
     get; 
    } 
} 

다음 IFooAttempt2<IAnimal>에 캐스트가 성공 :

class Program 
{ 
    static void Main(string[] args) 
    { 
     Attempt1(); 
     Attempt2(); 
    } 


    static void Attempt1() 
    { 
     FooAttempt1 foo = new FooAttempt1(); 
     Console.WriteLine(foo.Animal.MakeNoise()); 

     string className = foo.GetType().FullName; 

     // ----- 

     // get the assembly 
     Assembly assembly = typeof(FooAttempt1).Assembly; 

     // get the class 
     Type type = assembly.GetType(className, false, true); 

     // create an instance 
     ConstructorInfo constructor = type.GetConstructor(new Type[] { }); 

     IFooAttempt1 foo2 = (IFooAttempt1)constructor.Invoke(null); 
     Console.WriteLine(foo2.Animal.MakeNoise()); 

    } 


    static void Attempt2() 
    { 
     FooAttempt2 foo = new FooAttempt2(); 
     Console.WriteLine(foo.Animal.MakeNoise()); 

     string className = foo.GetType().FullName; 

     // ----- 

     // get the assembly 
     Assembly assembly = typeof(FooAttempt2).Assembly; 

     // get the class 
     Type type = assembly.GetType(className, false, true); 

     // create an instance 
     ConstructorInfo constructor = type.GetConstructor(new Type[] { }); 

     object o = constructor.Invoke(null); 
     IFooAttempt2<IAnimal> foo2 = (IFooAttempt2<IAnimal>) o; // << PROBLEM HERE 
     Console.WriteLine(foo2.Animal.MakeNoise()); 
    } 
} 


public interface IAnimal 
{ 
    string MakeNoise(); 
} 

public class Dog : IAnimal 
{ 
    public string MakeNoise() 
    { 
     return "Bark"; 
    } 
} 

public interface IFooAttempt1 
{ 
    IAnimal Animal 
    { 
     get; 
    } 
} 

public class FooAttempt1 : IFooAttempt1 
{ 
    public FooAttempt1() 
    { 
    } 

    public IAnimal Animal 
    { 
     get 
     { 
      return new Dog(); 
     } 
    } 
} 


public interface IFooAttempt2<T> 
    where T : IAnimal 
{ 
    T Animal 
    { 
     get; 
    } 
} 

public class FooAttempt2 : IFooAttempt2<Dog> 
{ 
    public FooAttempt2() 
    { 
    } 

    public Dog Animal 
    { 
     get 
     { 
      return new Dog(); 
     } 
    } 
} 
+0

잘 쓰여진 질문입니다. – aevitas

답변

2

당신은 T에서 IFooAttempt2 공변을 만들 수 있습니다.

관련 문제