其他分享
首页 > 其他分享> > 表达式树参数是否需要重用同一实例?

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

作者:互联网

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

这是不使用方法调用的样例(在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: variable ‘baseType’ of type ‘UserQuery+Test’ referenced from scope ”, but it is not defined

但是,如果我将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
}

解决方法:

是的,您需要引用之前使用的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"));

标签:c,expression-trees
来源: https://codeday.me/bug/20191127/2076689.html