표현 트리를 만들 때 다른 람다에서 하나의 람다를 만들고 클래스에서 내부 하나를 저장하고 해당 클래스를 표현 트리에 추가해야하는 상황이 있습니다. 이것은 내가 뭘하려고 오전의 간단한 예입니다 (이 코드는 컴파일되지 않습니다) :표현 트리 - 바깥 쪽 람다 범위 지정의 내부 람다 컴파일
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace SimpleTest {
public class LambdaWrapper {
private Delegate compiledLambda;
public LambdaWrapper(Delegate compiledLambda) {
this.compiledLambda = compiledLambda;
}
public dynamic Execute() {
return compiledLambda.DynamicInvoke();
}
}
public class ForSO {
public ParameterExpression Param;
public LambdaExpression GetOuterLambda() {
IList<Expression> lambdaBody = new List<Expression>();
Param = Expression.Parameter(typeof(object), "Param");
lambdaBody.Add(Expression.Assign(
Param,
Expression.Constant("Value of 'param' valiable"))
);
lambdaBody.Add(Expression.Call(
null,
typeof(ForSO).GetMethod("Write"),
Param)
);
Delegate compiledInnerLambda = GetInnerLambda().Compile();
LambdaWrapper wrapper = new LambdaWrapper(compiledInnerLambda);
lambdaBody.Add(Expression.Constant(wrapper));
//lambdaBody.Add(GetInnerLambda());
return Expression.Lambda(
Expression.Block(
new ParameterExpression[] { Param },
lambdaBody));
}
public LambdaExpression GetInnerLambda() {
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"))
)
);
}
public static void Write(object toWrite) {
Console.WriteLine(toWrite);
}
public static void Main(string[] args) {
ForSO so = new ForSO();
LambdaWrapper wrapper = so.GetOuterLambda().Compile()
.DynamicInvoke() as LambdaWrapper;
wrapper.Execute();
//(so.GetOuterLambda().Compile().DynamicInvoke() as Delegate).DynamicInvoke();
}
}
}
문제가 GetOuterLambda
방법 GetInnerLambda().Compile()
라인입니다. 코드의 주석 부분에 하나의 해결책이 있음을 알고 있습니다. 그 모든 일을 잘 작동하지만 반환 값으로 래퍼가 필요합니다. 식 서브 트리가 아닙니다. LambdaWrapper에 내부 람다 하위 트리를 저장하고 나중에 컴파일하면 문제가 발생하지만 같은 문제가 발생합니다.
오류가 발생했습니다. Unhandled Exception: System.InvalidOperationException: variable 'Param' of type 'System.Object' referenced from scope '', but it is not defined
입니다.
내부 람다 변수를 블록에 추가하면 코드가 컴파일되지만 Param은 외부 람다에 값이 할당되지 않습니다.
어떻게 해결할 수 있습니까? 당신의 LambdaWrapper
에
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
);
}
그런 다음 매개 변수의 값을 저장 : 당신은 당신의 내면의 람다 식의 상수 값으로 Param
를 사용할 수 없기 때문에
감사합니다.이 접근 방법에 대해 싫어하는 점은 그 람다가 실제 함수이며 매개 변수를 가질 수 있다는 것입니다 (문제가 없기 때문에 문제의 부분을 포함하지 않았습니다). Param은 변수 (많은 것들이있을 수 있습니다)에 액세스해야하므로 범위 지정을 해결하기 위해 인공 파라미터를 추가하는 것은 매우 세련된 솔루션이라고 생각하지 않습니다. –
업데이트 된 답변은 저에게 효과적 일지 모르지만 근무중인 컴퓨터로 돌아올 때를 확인해야합니다. 감사합니다 ... –
이것이 저에게 효과가 있는지 확인했습니다. 거의 :). 나는 한 단계 더 나아가 LambdaWrapper 인스턴스를 생성하기 위해 DynamicExpression을 만들었습니다. 나는 바인더를 만들어야했기 때문에이 영혼은 더 많은 일을 필요로하지만, 어쨌든 나는 주 프로젝트에서 그것들을 가지고 있었다. 이 문제를 해결해 주신 것에 감사드립니다. :) –