私はすべての要素を組み合わせる方法を理解しようとしています。簡単なケースから始めるための具体的なソースコードサンプルをいただければ幸いです。
次のC#コードを考えます。
Func<int, int, int> f = (x, y) => x + y;
次のように式ツリーを使用して、実行時に同等の関数を生成できます。
var x = Expression.Parameter(typeof(int), "x");
var y = Expression.Parameter(typeof(int), "y");
Func<int, int, int> f =
Expression.Lambda<Func<int, int, int>>(
Expression.Add(x, y),
new[] { x, y }
).Compile();
今、次のラムダが与えられました:
Func<dynamic, dynamic, dynamic> f = (x, y) => x + y;
式ツリー(および、おそらくExpression.Dynamic
)?
動的C#追加式のCallSiteBinderをExpression.Dynamicに渡すことにより、動的C#追加式を表す式ツリーを作成できます。元の動的式でReflectorを実行することにより、バインダーを作成するコードを発見できます。あなたの例は次のようになります:
var x = Expression.Parameter(typeof(object), "x");
var y = Expression.Parameter(typeof(object), "y");
var binder = Binder.BinaryOperation(
CSharpBinderFlags.None, ExpressionType.Add, typeof(Program),
new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
Func<dynamic, dynamic, dynamic> f =
Expression.Lambda<Func<object, object, object>>(
Expression.Dynamic(binder, typeof(object), x, y),
new[] { x, y }
).Compile();
式ツリーは「動的な操作を含んでいない可能性がある」ため、これは実行できません。
たとえば、+演算が原因で次のコードはコンパイルされず、そのルールに違反する式ツリーを構築しようとしています。
Expression<Func<dynamic, dynamic, dynamic>> f = (x, y) => x + y;
追加操作を行わなかった場合は、それでうまくいくでしょう。
詳細は Expression <Func <dynamic、dynamic >>を作成する方法-またはバグですか? を参照してください。
編集:
これは、動的パラメーターを受け取り、動的な結果を返す独自のAddメソッドを定義することで、可能な限り近くなります。
class Program
{
static void Main(string[] args)
{
var x = Expression.Parameter(typeof(object), "x");
var y = Expression.Parameter(typeof(object), "y");
Func<dynamic, dynamic, dynamic> f =
Expression.Lambda<Func<dynamic, dynamic, dynamic>>(
Expression.Call(typeof(Program), "Add", null, x, y),
new[] { x, y }
).Compile();
Console.WriteLine(f(5, 2));
Console.ReadKey();
}
public static dynamic Add(dynamic x, dynamic y)
{
return x + y;
}
}
とても興味深い。同じ理由で以下がコンパイルされないのは不可能だと思います:
Expression<Func<dynamic, dynamic, int>> func = (p1, p2) => p1 + p2;
これはコンパイラエラーCS1963です(これはMSによって文書化されていないようです)。
エラーCS1963:式ツリーに動的操作が含まれていない可能性があります