3

我正在使用反射和表达式树的组合,并希望将某些属性访问器从类传回调用方法。我当前的代码有一个遍历类并返回MemberExpressions 列表的方法。然后调用者遍历成员表达式并创建 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:从范围“”引用的“UserQuery+Test”类型的变量“baseType”,但未定义

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

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

也就是说,将 替换为Expression.Parameter之前使用的变量,然后它就可以工作了。在我想使用它的情况下,这不是(很容易)可能的,因为我必须将原始参数与列表一起返回(当然,我可以返回一个元组,但我不希望这样做,如果它是没有必要)。

为什么它会这样工作?检查DebugViewlambda,无论使用什么方法,它们都是完全相同的:

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

1 回答 1

3

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

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

在 lambda 中创建 newParameterExpression时,您正在做同样的事情(但请注意,在制作 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"));
于 2012-08-20T19:02:40.190 回答