如何在C#中引用lambda中的方法参数



给定此lambda

public static Expression<Func<int, int>> Add(int add)
{
return x => x + add;
}

它创建以下调试输出:

.Lambda #Lambda1<System.Func`2[System.Int32,System.Int32]>(System.Int32 $x) {
$x + .Constant<ConsoleAppExpressionTest.Program+<>c__DisplayClass1_0>(ConsoleAppExpressionTest.Program+<>c__DisplayClass1_0).add
}

debug视图显示字段add是在一个常量中寻址的。

如何动态创建相同的lambda?

我尝试过的:

public static Expression<Func<int, int>> Add(int add)
{
var x = Expression.Parameter(typeof(int), "x");
var expr = Expression.Add(x, Expression.Field(Expression.Constant(null), "add"));
return Expression.Lambda<Func<int, int>>(expr, x);
}

导致CCD_ 2。

而直接将参数用作常量只会创建值的副本:Expression.Constant(add)

这样做的诀窍是使用简单的Expression.Constant(add)Expression.Constant(add, typeof(int))(显式表达类型是个好主意,尤其是当值可以是null时(。


至于使用字段方法:您不能,第一个版本中的常规编译器也不能。编译器所做的是生成闭包,并使用

var obj = new SomeGeneratedClosureType();
obj.add = add; // and now *all* mentions of "add" use obj.add instead

并使用该对象作为中的常数

var expr = Expression.Add(x, Expression.Field(Expression.Constant(obj), "add"));

这个SomeGeneratedClosureType就是问题代码中的ConsoleAppExpressionTest.Program+<>c__DisplayClass1_0

然而,更高效、更直接而不是这样做,只需直接使用该值。编译器不能做到这一点,因为它需要对值的行为保持一定的保证,而如果直接使用值,这是不可能的。

我想这就是你想要的:

public static Expression<Func<int, int>> Add(int add)
{
var x = Expression.Parameter(typeof(int), "x");
var addExpression = Expression.Constant(add);
var expr = Expression.Add(x, addExpression);
return Expression.Lambda<Func<int, int>>(expr, x);
}

最新更新