存储和调用一般类型的委托

时间:2012-02-01 18:23:57

标签: c# generics delegates

如果不诉诸反思,我所寻找的东西可能是不可能的。如果是这种情况,我仍然想知道最好的办法。

基本上,这就是我希望我的代码看起来像:

var instance = new MyClass();
instance.Add<int, string>(x => x.ToString());
instance.Add<string, Warehouse>(x => Warehouse.LookupByName(x));
instance.Add<Warehouse, IList<Supplier>>(x => x.Suppliers());

instance.Chain(3);    // should call each lambda expression in turn

我的问题是,如何在MyClass的列表中存储这些具有不同签名的代理?以后如何在我想要的时候调用它们,使用每个的返回值作为下一个的输入参数?

MyClass的内部很可能是List的混乱和所有这一切。但我甚至不确定从哪里开始。

(原来,我想打电话给new MyClass<int, string, Warehouse, IList<Supplier>>()。但是,由于没有“类型参数数组”,我放弃了这种方法。)

4 个答案:

答案 0 :(得分:11)

好吧,你可以将它们全部存储为Delegate - 但是棘手的是稍后再调用它们。

如果您能够在任何时候验证下一个代表的类型是否正确,例如通过为“当前输出”保留Type引用,您始终可以存储List<Func<object, object>>并使Add方法类似:

public void Add<TIn, TOut>(Func<TIn, TOut> func)
{
    // TODO: Consider using IsAssignableFrom etc
    if (currentOutputType != typeof(TIn))
    {
        throw new InvalidOperationException(...);
    }
    list.Add(o => (object) func((TIn) o));
    currentOutputType = typeof(TOut);
}

然后全部调用它们:

object current = ...; // Wherever
foreach (var func in list)
{
    current = func(current);
}

答案 1 :(得分:2)

Linq Select语句基本上就是这样......

var temp = instance.Select(x => x.ToString())
.Select(x => WareHouse.LookupByName(x))
.Select(x=> x.Suppliers());

List<List<Suppliers>> = temp.ToList(); //Evaluate statements

您还可以将每个中间选择调用存储为Enumerable,以使用您在OP中使用的声明方法。

答案 2 :(得分:0)

class Program
{
    static void Main(string[] args)
    {
        var instance = new MyClass();
        instance.Add<int, string>(i => i.ToString());
        instance.Add<string, int>(str => str.Length);
        instance.Add<int, int>(i => i*i);

        Console.WriteLine(instance.Chain(349));
        Console.ReadLine();

    }
}

public class MyClass
{
    private IList<Delegate> _Delegates = new List<Delegate>();

    public void Add<InputType, OutputType>(Func<InputType, OutputType> action)
    {
        _Delegates.Add(action);
    }

    public object Chain<InputType>(InputType startingArgument)
    {
        object currentInputArgument = startingArgument;
        for (var i = 0; i < _Delegates.Count(); ++i)
        {
            var action = _Delegates[i];
            currentInputArgument = action.DynamicInvoke(currentInputArgument);
        }
        return currentInputArgument;
    }
}

答案 3 :(得分:0)

如果你想要编译时类型检查,你所做的事情听起来像普通的旧通用代表一样可疑。假设存储Add的各个函数(除了Int到String转换除外)并稍后编写它们有一些价值,你可以这样做:

var lookupWarehouseByNumber = new Func<int, Warehouse>(i => Warehouse.LookupByName(i.ToString()));
var getWarehouseSuppliers = new Func<Warehouse, IEnumerable<Supplier>>(w => w.Suppliers);
var getWarehouseSuppliersByNumber = new Func<int, IEnumerable<Supplier>>(i => getWarehouseSuppliers(lookupWarehouseByNumber(i)));