代码之家  ›  专栏  ›  技术社区  ›  TheCloudlessSky

如何在“sub”表达式中使用lambda表达式参数?

  •  4
  • TheCloudlessSky  · 技术社区  · 14 年前

    我希望能够生成如下委托的表达式:

    Func<object[], object> 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<object[], object>>.Lambda<Func<object[], object>>(
                someType1Exp,
                Expression.Parameter(typeof(object[])));
    

    我很难理解如何将参数从外部表达式“传递”到内部表达式,然后将其转换为正确的类型。

    任何方向正确的提示都是值得赞赏的。

    1 回复  |  直到 14 年前
        1
  •  3
  •   Marc Gravell    14 年前

    我在iPod上,所以目前不能给出完整的例子:但是:

    • 声明object[]类型的参数( Expression.Param(typeof(object[])) )并将其存储在变量中
    • 索引器 获取索引器的表达式,并且“ Convert 或“演员”(又是iPod!)投球
    • 使用 Expression.Invoke ,传递内部表达式和上面生成的indexer+cast

    如果你需要的话,我很乐意稍后再做一个完整的例子(当我在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<Func<object[], object>>(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<Func<object[], object>>(body, args);
    var func = outer.Compile();
    
    object[] values = {1, 123.45F, "abc"};
    object obj = func(values);
    Console.WriteLine(obj);