表达式树参数是否需要重用同一实例?
作者:互联网
我正在使用反射树和表达式树的组合,并希望将某些属性访问器从类传递回调用方法.我当前的代码中有一个遍历类并返回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