如果不诉诸反思,我所寻找的东西可能是不可能的。如果是这种情况,我仍然想知道最好的办法。
基本上,这就是我希望我的代码看起来像:
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>>()
。但是,由于没有“类型参数数组”,我放弃了这种方法。)
答案 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)));