我正在使用反射和表达式树的组合,并希望将某些属性访问器从类传递回调用方法。我当前的代码有一个遍历类并返回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
}
答案 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"));