簡體   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