这是因为编译器创建了一个在闭包中捕获factor
变量的委托对象。
实际上,如果你使用反编译工具,你会看到以下代码被生成:
public static Func<int, int> AssignLocalFunctionToDelegate()
{
int factor = 3;
return delegate (int x) {
return (factor * x);
};
}
你可以看到factor
将被捕获在闭包中 (你可能已经知道编译器会生成一个包含字段来保存factor
的类.)
在我的机器上,它会创建以下类作为闭包:
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public int factor;
internal int <AssignLocalFunctionToDelegate>g__Triple0(int x)
{
return (this.factor * x);
}
}
如果我将AssignLocalFunctionToDelegate()
更改为
public static Func<int, int> AssignLocalFunctionToDelegate()
{
int factor;
int Triple(int x) => factor * x;
factor = 3;
Console.WriteLine(Triple(2));
return Triple;
}
那么实现就变成了:
public static Func<int, int> AssignLocalFunctionToDelegate()
{
<>c__DisplayClass1_0 CS$<>8__locals0;
int factor = 3;
Console.WriteLine(CS$<>8__locals0.<AssignLocalFunctionToDelegate>g__Triple0(2));
return delegate (int x) {
return (factor * x);
};
}
你可以看到它创建了编译器生成的类的实例,并将其用于Console.WriteLine()。
但你无法在反编译后的代码中看到它实际上是在哪里给factor
赋值为3
。要查看这一点,你必须查看IL本身(这可能是我使用的反编译器的缺陷,该反编译器相当老)。
IL看起来像这样:
L_0009: ldc.i4.3
L_000a: stfld int32 ConsoleApp3.Program/<>c__DisplayClass1_0::factor
这将加载一个常量值 3 并将其存储在编译器生成的闭包类的 factor
字段中。
Expression<T>
。请参见Local function vs Lambda C# 7.0。 - Olivier Jacot-Descombes