简体   繁体   English

C#在抽象类中转换泛型T <T> 动态

[英]C# cast generic T in abstract class<T> to dynamic

This is what I want to do in C# (within class Helper - without generic arguments), 这就是我想在C#中做的(在class Helper -没有通用参数),

List<AbstractClass<dynamic>> data;

public void Add<T>(AbstractClass<T> thing)
{
    this.data.Add((AbstractClass<dynamic>) thing);
}

This helper class would take and work with AbstractClass<> objects and give back AbstractClass<> of specific generic type. 该帮助器类将使用AbstractClass<>对象并与之一起工作,并返回特定泛型的AbstractClass<> AbstractClass<T> contains many functions which return T / take in T like public T Invoke() . AbstractClass<T>包含许多返回T / T函数,例如public T Invoke() For Helper class T cannot be known beforehand. 对于助手类, T不能事先知道。 The Add<T>(.. thing) function is not in a class of type T . Add<T>(.. thing)函数不在T类型的类中。 To be used like this in Helper class's functions, 要在Helper类的函数中像这样使用,

foreach(var c in data.Where(x => ...))
{
    // public T Invoke() { ... } function within AbstractClass<T>
    var b = c.Invoke(); 
    // logic
}

This also fails, 这也失败了

List<AbstractClass<object>> data;

public void Add<T>(AbstractClass<T> thing)
{
    this.data.Add((AbstractClass<object>) thing);
}

Now I think I can have, 现在我想我可以拥有

List<dynamic> data; // or List<object> data;

public void Add<T>(AbstractClass<T> thing)
{
    this.data.Add(thing);
}

but I want the constraint that List named data has only elements of type like 但我想要约束List命名数据仅具有以下类型的元素

ConcreteClass : AbstractClass<OtherClass>

So we would know that there is an public T Invoke() function but we do not know what it returns. 因此,我们知道有一个public T Invoke()函数,但我们不知道它返回什么。 This is helpful to avoid mistakes of say misspelling Invocke and only knowing at run-time. 这有助于避免说错拼写Invocke以及仅在运行时知道的错误。

I want to avoid casting to dynamic every time to invoke functions that give back generic type T 我想避免每次转换为dynamic函数时都调用返回通用类型T的函数

To do what you want to do you are going to need to use a Contravariant interface 要执行您想做的事情,您将需要使用Contravariant接口

public class Program
{
    static void Main()
    {
        var m = new Helper();
        m.Add(new ConcreteClass());

        m.Process();
    }

    class Helper
    {
        List<IAbstractClass<OtherClassBase>> data = new List<IAbstractClass<OtherClassBase>>();

        public void Add(IAbstractClass<OtherClassBase> thing)
        {
            this.data.Add(thing);
        }

        public void Process()
        {
            foreach(var c in data.Where(x => x.ShouldBeProcessed()))
            {
                var b = c.Invoke();
                Console.WriteLine(b.Question);
                var castData = b as OtherClass;
                if (castData != null)
                    Console.WriteLine(castData.Answer);
            }
        }
    }

    public interface IAbstractClass<out T>
    {
        bool ShouldBeProcessed();
        T Invoke();
    }

    abstract class AbstractClass<T> : IAbstractClass<T>
    {
        public bool ShouldBeProcessed()
        {
            return true;
        }

        public abstract T Invoke();
    }

    class ConcreteClass : AbstractClass<OtherClass>
    {
        public override OtherClass Invoke()
        {
            return new OtherClass();
        }
    }


    class OtherClassBase
    {
        public string Question { get { return "What is the answer to life, universe, and everything?"; } }
    }

    class OtherClass : OtherClassBase
    {
        public int Answer { get { return 42; } }
    }
}

You do not need to tell Add what kind of class you are passing it, all that matters is it derives from the type specified. 您无需告诉Add您要传递哪种类型的类,重要的是它是从指定的类型派生的。 You could do public void Add(IAbstractClass<object> thing) and every class would work, but Invoke() would only return objects inside the foreach loop. 您可以执行public void Add(IAbstractClass<object> thing) ,每个类都可以工作,但是Invoke()仅会在foreach循环内返回对象。

You need to figure out what is the most derived class you want Invoke() to return and that is what you set as the type in the list. 您需要弄清楚什么是Invoke()返回的最派生类,这是您在列表中设置的类型。

Maybe this will work for you: 也许这将为您工作:

public class Program
{
    static void Main()
    {
        var m1 = new Helper<OtherClass>();
        m1.Add(new ConcreteClass());
        var m2 = new Helper<int>();
        m2.Add(new ConcreteClass2());
    }
    class Helper<T>
    {
        List<AbstractClass<T>> data = new List<AbstractClass<T>>();

        public void Add<T1>(T1 thing) where T1 : AbstractClass<T>
        {
            this.data.Add(thing);
        }
    }
    class AbstractClass<T> { }
    class OtherClass { }
    class ConcreteClass : AbstractClass<OtherClass> { }
    class ConcreteClass2 : AbstractClass<int> { }
}

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

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