如何在“sub”表达式中使用lambda表达式参数?
我希望能够像下面的委托一样构建表达式:
Func createSomeType1 = (args) => { return new SomeType1((P1)args[0], (P2)args[1], (P3)args[2]); };
我刚开始用手工制作的表达式,请原谅我这是一个相当简单的问题(或者我误解了一些问题)。
我知道要使用正确的类型创建构造函数,我会执行以下操作:
var p1 = Expression.Parameter(typeof(P1)); var p2 = Expression.Parameter(typeof(P2)); var p3 = Expression.Parameter(typeof(P3)); var someType1Exp = Expression.New(constructorInfo, p1, p2, p3);
然后我知道,“外部”lambda,我认为,这样声明:
Expression<Func>.Lambda<Func>( someType1Exp, Expression.Parameter(typeof(object[])));
我无法绕过如何将参数从外部表达式“传递”到内部表达式,然后将其转换为正确的类型。
任何正确方向的提示都值得赞赏。
我在iPod上,所以现在不能给出一个完整的例子:但是:
- 声明一个类型为object [](
Expression.Param(typeof(object[]))
)的参数并将其存储在一个变量中 - 对于数组中的每个术语,使用数组索引器获取索引器的表达式,并使用“
Convert
”或“Convert
”(再次使用iPod!)来转换它 - 使用
Expression.Invoke
,传递内部表达式加上上面生成的索引器+转换
如果你需要(我在PC的时候),我会很乐意做一个完整的例子
完整示例:
Type[] types = new Type[] { typeof(int), typeof(float), typeof(string) }; var constructorInfo = typeof(SomeType).GetConstructor(types); var parameters = types.Select((t,i) => Expression.Parameter(t, "p" + i)).ToArray(); var someType1Exp = Expression.New(constructorInfo, parameters); var inner = Expression.Lambda(someType1Exp, parameters); var args = Expression.Parameter(typeof(object[]), "args"); var body = Expression.Invoke(inner, parameters.Select((p,i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), p.Type)).ToArray()); var outer = Expression.Lambda>(body, args); var func = outer.Compile(); object[] values = {1, 123.45F, "abc"}; object obj = func(values); Console.WriteLine(obj);
或者作为单个表达式:
Type[] types = new Type[] { typeof(int), typeof(float), typeof(string) }; var constructorInfo = typeof(SomeType).GetConstructor(types); var args = Expression.Parameter(typeof(object[]), "args"); var body = Expression.New(constructorInfo, types.Select((t,i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), t)).ToArray()); var outer = Expression.Lambda>(body, args); var func = outer.Compile(); object[] values = {1, 123.45F, "abc"}; object obj = func(values); Console.WriteLine(obj);