2014-06-18 47 views
1

我有一个奇怪的反射问题。使用反射来创建实现类型为T的接口的类

请参阅类FooAttempt1,该类实现接口IFooAttempt1,该接口具有返回IAnimal的属性。在FooAttempt1的情况下,它返回Dog

在有问题的程序中,实现IFooAttempt1的类会被实例化,做一些工作,然后将它们自己的反射类型和一个键存储到数据库中,然后使用反射进行重新水化。有很多这样的类实现IFooAttempt1,它是一个工作得很好的体系结构。

您可以在方法Attempt1()中看到工作中的基本过程。

问题是,真实的类比IFooAttempt1稍微复杂一些,很容易犯一个错误。因此,我们稍微重构了代码以使用泛型来帮助确保这些类正确实现。

请参阅FooAttempt2,它实现了一个通用的interface IFooAttempt2 <T> where T : IAnimal

这确保了动物属性现在定义为

public Dog Animal 

而不是

public IAnimal Animal 

两个IFooAttempt1IFooAttempt2在功能上是相同的,但仿制药的这种自我记录功能使得执行我们相当多复杂的类非常简单。

当您参考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} 

所以它正确地反映。即使FooAttempt2被定义为IFooAttempt2<Dog>,我也不能将它投射到(IFooAttempt2<IAnimal>),其中DogIAnimal

我马上想到,试图做到这一点

Type type = assembly.GetType(className, false, true).MakeGenericType(new[] { typeof(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

你可以在TIFooAttempt2协变:

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

然后投给IFooAttempt2<IAnimal>会成功。

相关问题