C#将抽象类<t>中的泛型T转换为动态</t>

时间:2013-08-02 15:43:18

标签: c# generics dynamic

这就是我想在C#中做的事情(在class Helper内 - 没有通用参数),

List<AbstractClass<dynamic>> data;

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

此助手类将使用AbstractClass<>个对象并返回特定泛型类型的AbstractClass<>AbstractClass<T>包含许多函数,这些函数返回T / T,如public T Invoke()。 对于Helper类T,事先无法知道。 Add<T>(.. thing)函数不在T类中。 要在Helper类的函数中使用,

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

这也失败了,

List<AbstractClass<object>> data;

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

现在我想我可以拥有,

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

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

但我希望List命名数据只有像

这样的元素的约束
ConcreteClass : AbstractClass<OtherClass>

所以我们知道有一个public T Invoke()函数,但我们不知道它返回了什么。这有助于避免错误拼写错误的Invocke并且只在运行时知道。

我想避免每次调用dynamic来调用返回泛型类型T的函数

2 个答案:

答案 0 :(得分:1)

要做你想做的事,你需要使用Contravariant interface

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

你不需要告诉Add你传递的类是什么类,重要的是它是从指定的类型派生出来的。您可以执行public void Add(IAbstractClass<object> thing)并且每个类都可以工作,但Invoke()只返回foreach循环内的对象。

你需要弄清楚你希望Invoke()返回的派生类最多的是什么,这就是你在列表中设置的类型。

答案 1 :(得分:0)

也许这对你有用:

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> { }
}