表达式树参数是否需要重用相同的实例?

时间:2012-08-20 18:53:48

标签: c# expression-trees

我正在使用反射和表达式树的组合,并希望将某些属性访问器从类传递回调用方法。我当前的代码有一个遍历类并返回MemberExpression列表的方法。然后调用者遍历成员表达式并创建lambdas,然后使用被检查类的实例调用该lambdas以返回属性的值。

以下是没有方法调用(LINQPad中的Runnable)的样子:

void Main()
{
    var t = new Test { Prop = "Test" };

    var property = t.GetType().GetProperty("Prop");

    var baseType = Expression.Parameter(typeof(Test), "baseType");
    var memberAccess = Expression.MakeMemberAccess(baseType, property);
    var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
    var func = lambda.Compile();
    var result = func(t);
    result.Dump();
}

class Test {
    public string Prop { get; set; }
}

这不起作用,抛出此异常:

  

InvalidOperationException:从范围''引用的'UserQuery + Test'类型的变量'baseType',但它未定义

但是,如果我将lambda的创建更改为:

var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, baseType);

也就是说,用先前使用的变量替换Expression.Parameter,然后它就可以了。在我想要使用它的场景中,这不是(容易)可能的,因为我必须将原始参数与列表一起返回(当然,我可以返回一个元组,但我不愿意,如果它是不必要)。

为什么它会像这样工作?无论采用何种方法,检查lambda的DebugView都是完全相同的:

.Lambda #Lambda1<System.Func`2[UserQuery+Test,System.String]>(UserQuery+Test $baseType)
{
    $baseType.S
}

1 个答案:

答案 0 :(得分:3)

是的,您需要参考之前使用过的ParameterExpression。这也不会编译:

private String Foo(Test myParam)
{
  return myAnotherParam.MyProperty;
}

在lambda中设置新的ParameterExpression,你做的是同样的事情(但请注意,在制作lambda时,你是按相反的顺序进行的 - 首先,你正在构建一个方法体,然后 - 方法声明):

// return myAnotherParam.MyProperty;
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);

// private String Foo(MyClass myParam)
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));