Well, since you cannot use Param
as a constant value in your internal lambda expression, I suggest you add the lambda parameter to your expression:
public LambdaExpression GetInnerLambda() { var param = Expression.Parameter(typeof(object)); return Expression.Lambda( Expression.Block( Expression.Call(null, typeof(ForSO).GetMethod("Write"), Expression.Constant("Inner lambda start")), Expression.Call(null, typeof(ForSO).GetMethod("Write"), param), Expression.Call(null, typeof(ForSO).GetMethod("Write"), Expression.Constant("Inner lambda end")) ), param ); }
Then, save the value of the parameter in the LambdaWrapper
class and use it later as an argument in the DynamicInvoke
call:
public class LambdaWrapper { private object param; private Delegate compiledLambda; public LambdaWrapper(Delegate compiledLambda, object param) { this.compiledLambda = compiledLambda; this.param = param; } public dynamic Execute() { return compiledLambda.DynamicInvoke(param); } }
This works, but the only problem is that it will call WriteLine
on Param
, which is a ParameterExpression object. To solve this problem, you must dynamically create a wrapper class in your expression tree:
//lambdaBody.Add(Expression.Constant(wrapper)); lambdaBody.Add(Expression.New( typeof(LambdaWrapper).GetConstructor(new[] { typeof(Delegate), typeof(object) }), Expression.Constant(compiledInnerLambda), Param) );
Then it will use the assigned value of Param
. And since you are not using Param
outside GetOuterLambda
, now you can use it as a local variable.
EDIT:
Here is my second attempt to solve this problem:
public LambdaExpression GetOuterLambda() { ... //Delegate compiledInnerLambda = GetInnerLambda().Compile(); //LambdaWrapper wrapper = new LambdaWrapper(compiledInnerLambda); lambdaBody.Add(Expression.New( typeof(LambdaWrapper).GetConstructor(new[] { typeof(Delegate) }), Expression.Call( Expression.Call( typeof(ForSO).GetMethod("GetInnerLambda", BindingFlags.Public | BindingFlags.Static), Param ), typeof(LambdaExpression).GetMethod("Compile", Type.EmptyTypes) ) )); ... } public static LambdaExpression GetInnerLambda(object param) { return Expression.Lambda( Expression.Block( Expression.Call(null, typeof(ForSO).GetMethod("Write"), Expression.Constant("Inner lambda start")), Expression.Call(null, typeof(ForSO).GetMethod("Write"), Expression.Constant(param)), Expression.Call(null, typeof(ForSO).GetMethod("Write"), Expression.Constant("Inner lambda end")) ) ); }
This approach compiles this inner lambda when running an external delegate. By doing this, Param
will be assigned before the inner lambda is compiled.