私は式ツリーを作成しています。別のラムダで1つのラムダを作成し、クラスの内部のものを格納し、そのクラスを式ツリーに追加する必要がある状況があります。 これは私がやろうとしています何の簡単な例である(このコードはコンパイルされません):式ツリー - 外側のラムダスコープの解像度で内側のラムダをコンパイル
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()
ラインです。 私は1つの解決策を認識しています - コードのコメント部分にあります。これで、すべて正常に動作しますが、式のサブツリーではなく、戻り値としてラッパーが必要です(LambdaWrapperに内部ラムダサブツリーを格納し、後でコンパイルするのは問題ありませんが同じ問題が発生します)。
エラーが発生しましたUnhandled Exception: System.InvalidOperationException: variable 'Param' of type 'System.Object' referenced from scope '', but it is not defined
です。
内側のラムダのブロック変数にParam
を追加すると、コードはコンパイルされますが、Paramは外側のラムダに値が割り当てられていません(意味があります)。
どうすれば解決できますか?まあ
ありがとう:
これは私の最終的な解決策です。私がこのアプローチについて気に入らないのは、それらのラムダが実際の関数であり、パラメータを持つことができるということです(私はそれに問題がないので、問題の部分は含めませんでした).Paramは、私はアクセスする必要があります(それらの多くがある可能性があります)ので、私はスコープを解決するために人工的なパラメータをaddigは非常にエレガントなソリューションだとは思わない。 –
更新された回答は私にとってはうまくいくかもしれませんが、私はいつ仕事用のコンピュータに戻ってくるかを確認する必要があります。ありがとう... –
これは私のために働くかどうかを確認しました。ほとんど:)私はそれをさらに一歩進め、LambdaWrapperのインスタンスを作成するためのDynamicExpressionを作成しました。私はバインダーを作る必要があったので、この作品はもっと多くの作業が必要ですが、私の主なプロジェクトではすでに持っていました。この問題を解決してくれたことに感謝します:) –