简体   繁体   English

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

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

I have a strange reflection problem. 我有一个奇怪的反思问题。

Refer to the class FooAttempt1 that implements the interface IFooAttempt1 which has a property that returns an IAnimal . 请参阅实现接口IFooAttempt1的类FooAttempt1 ,该接口具有返回IAnimal的属性。 In the case of FooAttempt1 it is returning a Dog . FooAttempt1的情况下,它将返回Dog

In the program in question, our classes that implement IFooAttempt1 are instantiated, do some work and then store their own reflected type and a key to the database and are later rehydrated using reflection. 在所讨论的程序中,将实例化实现IFooAttempt1的类,进行一些工作,然后将其自身的反射类型和键存储到数据库中,然后使用反射将其重新水化。 There are many such classes that implement IFooAttempt1 and it is an architecture that is working quite well. 有许多实现IFooAttempt1类,并且它是一种运行良好的体系结构。

You can see the basic process at work in the method Attempt1() . 您可以在Attempt1()方法中看到工作的基本过程。

The problem is that that real classes are slightly more complex than IFooAttempt1 and it is easy to make a mistake. 问题在于,实型IFooAttempt1稍微复杂IFooAttempt1 ,并且很容易犯错误。 As such we have refactored the code slightly to use generics to help ensure that these classes are implemented correctly. 因此,我们对代码进行了一些重构,以使用泛型来帮助确保正确实现这些类。

Refer to FooAttempt2 which implements a generic interface IFooAttempt2 < T > where T : IAnimal . 请参阅FooAttempt2 ,它实现了通用interface IFooAttempt2 < T > where T : IAnimal

This ensures that the Animal property is now defined as 这样可以确保将Animal属性现在定义为

public Dog Animal

rather than 而不是

public IAnimal Animal

Both IFooAttempt1 and IFooAttempt2 are functionally identical but this self-documenting feature of generics makes implementing our rather more complex classes very simple. IFooAttempt1IFooAttempt2在功能上是相同的,但是泛型的这种自记录功能使实现我们相当复杂的类非常简单。

The problem comes when you refer to the Attempt2() code. 当您引用Attempt2()代码时,就会出现问题。 When using reflection to recreate FooAttempt2 the line 使用反射重新创建FooAttempt2

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

displays the error 显示错误

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]'.

I can understand its point but how do you do this using reflection? 我能理解它的意思,但是如何使用反射来做到这一点呢?

In the immediate window, if you go 在即时窗口中,如果您转到

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

so it has reflected correctly. 因此已正确反映。 I just can't cast it to a ( IFooAttempt2<IAnimal> ) even though FooAttempt2 is a defined as IFooAttempt2<Dog> where Dog is an IAnimal . 即使FooAttempt2被定义为IFooAttempt2<Dog> ,其中DogIAnimal我也无法将其转换为( IFooAttempt2<IAnimal> )。

My immediate thought was to try to do this 我立即想到的是尝试这样做

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

but it does not compile. 但它不能编译。 Evidently the compiler does not like the typeof(interface) 显然,编译器不喜欢typeof(interface)

At this stage I am totally stuck. 在这一阶段,我完全陷入困境。

Thanks! 谢谢!

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

You can make IFooAttempt2 covariant in T : 您可以在T中使IFooAttempt2协变量:

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

then the cast to IFooAttempt2<IAnimal> will succeed. 那么对IFooAttempt2<IAnimal>将成功。

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

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