我正在试图找出如何将所有部分组合在一起,并希望能够从一个简单的案例开始一个具体的源代码示例。
考虑以下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();
现在给出以下lambda:
Func<dynamic, dynamic, dynamic> f = (x, y) => x + y;
我如何使用表达式树生成等价物(大概是Expression.Dynamic
)?
答案 0 :(得分:54)
您可以通过将动态C#添加表达式的CallSiteBinder传递给Expression.Dynamic来创建表示动态C#添加表达式的表达式树。您可以通过在原始动态表达式上运行Reflector来发现创建Binder的代码。你的例子会是这样的:
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();
答案 1 :(得分:2)
您不能这样做,因为表达式树“可能不包含动态操作”。
例如,由于+操作,以下将无法编译,并且您正在尝试构建违反该规则的表达式树:
Expression<Func<dynamic, dynamic, dynamic>> f = (x, y) => x + y;
如果您没有进行添加操作,则可以使用它。
有关详细信息,请参阅How to create an Expression<Func<dynamic, dynamic>> - Or is it a bug?。
编辑:
通过定义我自己的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;
}
}
答案 2 :(得分:1)
非常有趣。我想这是不可能的,因为下面的代码不能编译:
Expression<Func<dynamic, dynamic, int>> func = (p1, p2) => p1 + p2;
这是编译器错误CS1963(MS似乎没有记录):
错误CS1963:表达式树可能不包含动态操作