While the exception message is far from clear, I think you just encountered a limitation of the Expression
compiler: you can't have complicated subexpressions under a call expression to a method with ref
parameters.
I think what you should do to fix this is basically the same thing you would do in C# code: use a local variable to keep the intermediate result:
var child = Expression.Variable(typeof(object), "child");
var body = Expression.Block(
new[] { child },
Expression.Assign(child, CreateExpression("Child", proxyParameter)),
CreateExpression("Name", child));
var expr = Expression.Lambda<Func<Proxy, object>>(body, proxyParameter);
With this change, the code no longer throws an exception.
Also, you don't need to use Label
and Return
in your tryGetMember
expression. Instead, you could replace IfThenElse
with Condition
(basically, ternary operator from C#). If you do this, you also need to specify the type of Throw
(even though it never actually returns):
var tryGetMember =
Expression.Block(
new[] { result },
Expression.Condition(
Expression.Equal(
Expression.Call(
proxyParameter, tryGetMemberMethod, parent,
Expression.Constant(propertyName), result),
Expression.Constant(true)),
result,
Expression.Throw(
Expression.Constant(new MissingMemberException(propertyName)),
typeof(object))));