Expression Treeを呼び出し可能なメソッドC#にコンパイルするにはどうすればよいですか?
-
19-08-2019 - |
質問
C#の式クラスを使用してXmlを解析して作成した式ツリーがあります。 この質問を見る。
式ツリーには、加算、減算、除算、乗算、パラメータ、および/またはしかありません。 このExpressionTreeを呼び出し可能なメソッドに変換する方法はありますか? ...または手動でILを発行する必要がありますか?
よろしく、
解決
両方のアプローチの例を次に示します。何か見逃した場合、または詳細情報が必要な場合は、お知らせください。
static void Main()
{
// try to do "x + (3 * x)"
var single = BuildSingle<decimal>();
var composite = BuildComposite<decimal>();
Console.WriteLine("{0} vs {1}", single(13.2M), composite(13.2M));
}
// utility method to get the 3 as the correct type, since there is not always a "int x T"
static Expression ConvertConstant<TSource, TDestination>(TSource value)
{
return Expression.Convert(Expression.Constant(value, typeof(TSource)), typeof(TDestination));
}
// option 1: a single expression tree; this is the most efficient
static Func<T,T> BuildSingle<T>()
{
var param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Add(param, Expression.Multiply(
ConvertConstant<int, T>(3), param));
var lambda = Expression.Lambda<Func<T, T>>(body, param);
return lambda.Compile();
}
// option 2: nested expression trees:
static Func<T, T> BuildComposite<T>()
{
// step 1: do the multiply:
var paramInner = Expression.Parameter(typeof(T), "inner");
Expression bodyInner = Expression.Multiply(
ConvertConstant<int, T>(3), paramInner);
var lambdaInner = Expression.Lambda(bodyInner, paramInner);
// step 2: do the add, invoking the existing tree
var paramOuter = Expression.Parameter(typeof(T), "outer");
Expression bodyOuter = Expression.Add(paramOuter, Expression.Invoke(lambdaInner, paramOuter));
var lambdaOuter = Expression.Lambda<Func<T, T>>(bodyOuter, paramOuter);
return lambdaOuter.Compile();
}
個人的には、最初の方法を目指します。それはよりシンプルでより効率的です。これには、ネストされたコードのスタック全体に元のパラメーターを渡すことが含まれる場合がありますが、そうです。 <!> quot; Invoke <!> quot;をとるコードをどこかに持っています。アプローチ(複合)、および最初のアプローチ(単一)としてツリーを書き直します-しかし、それは非常に複雑で長いです。ただし、Entity Framework(Expression.Invokeをサポートしない)には非常に便利です。
所属していません StackOverflow