我正在使用反射树和表达式树的组合,并希望将某些属性访问器从类传回调用方法。我当前的代码有一个遍历类并返回 MemberExpression
列表的方法。然后,调用者遍历成员表达式并创建 lambda,然后应使用被检查类的实例调用它以返回属性的值。
这是一个没有方法调用的示例(在 LINQPad 中可运行):
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# - 表达式树参数是否需要重用相同的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12043390/