I’m using a combination of reflection and expression trees, and want to pass back certain property accessors from a class to a calling method. My current code has a method traversing the class and returning a list of MemberExpressions. The caller then iterates over the member expressions and creates lambdas, which should then be called with an instance of the inspected class to return the value of the property.
Here is a sample of what it would look like without the method calls (Runnable in 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; }
}
This does not work, throwing this exception:
InvalidOperationException: variable ‘baseType’ of type ‘UserQuery+Test’ referenced from scope ”, but it is not defined
However, if I change the creation of the lambda to this:
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, baseType);
That is, replace the Expression.Parameter with the variable used earlier, then it works. This is not (easily) possible in the scenario where I want to use it, since I would have to return the original parameter along with the list (I could return a tuple, of course, but I would prefer not to, if it is not necessary).
Why does it work like this? Inspecting the DebugView of the lambda, they are exactly the same no matter what approach is used:
.Lambda #Lambda1<System.Func`2[UserQuery+Test,System.String]>(UserQuery+Test $baseType)
{
$baseType.S
}
Yes, you need to refer
ParameterExpression, used earlier. This won’t compile too:With instatiating new
ParameterExpressionin lambda, you’re doing the same thing (but note, when making lambda, you’re doing it in reversed order – first, you’re constructing a method body, then – a method declaration):