繁体   English   中英

使用反射创建实现T类型接口的类

[英]Using reflection to create a class that implements an interface of type T

我有一个奇怪的反思问题。

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

在所讨论的程序中,将实例化实现IFooAttempt1的类,进行一些工作,然后将其自身的反射类型和键存储到数据库中,然后使用反射将其重新水化。 有许多实现IFooAttempt1类,并且它是一种运行良好的体系结构。

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

问题在于,实型IFooAttempt1稍微复杂IFooAttempt1 ,并且很容易犯错误。 因此,我们对代码进行了一些重构,以使用泛型来帮助确保正确实现这些类。

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

这样可以确保将Animal属性现在定义为

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> ,其中DogIAnimal我也无法将其转换为( IFooAttempt2<IAnimal> )。

我立即想到的是尝试这样做

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

但它不能编译。 显然,编译器不喜欢typeof(interface)

在这一阶段,我完全陷入困境。

谢谢!

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();
        }
    }
}

您可以在T中使IFooAttempt2协变量:

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

那么对IFooAttempt2<IAnimal>将成功。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM