问题描述
在C#7.0中,您可以声明局部函数,即位于另一种方法内部的函数.这些局部函数可以访问周围方法的局部变量.由于局部变量仅在调用方法时才存在,因此我想知道是否可以将局部函数分配给委托(该委托的寿命可以长于此方法调用的时间).
In C# 7.0 you can declare local functions, i.e. functions living inside another method. These local functions can access local variables of the surrounding method. Since the local variables exist only while a method is being called, I wondered whether a local function could be assigned to a delegate (which can live longer than this method call).
public static Func<int,int> AssignLocalFunctionToDelegate()
{
int factor;
// Local function
int Triple(int x) => factor * x;
factor = 3;
return Triple;
}
public static void CallTriple()
{
var func = AssignLocalFunctionToDelegate();
int result = func(10);
Console.WriteLine(result); // ==> 30
}
它确实有效!
我的问题是:为什么这样做有效?这是怎么回事?
My question is: why does this work? What is going on here?
推荐答案
之所以有效,是因为编译器创建了一个委托,该委托捕获了闭包中的 factor
变量.
This works because the compiler creates a delegate which captures the factor
variable in a closure.
实际上,如果您使用反编译器,则会看到生成以下代码:
In fact if you use a decompiler, you'll see that the following code is generated:
public static Func<int, int> AssignLocalFunctionToDelegate()
{
int factor = 3;
return delegate (int x) {
return (factor * x);
};
}
您会看到 factor
将在闭包中捕获.(您可能已经知道,在后台编译器将生成一个类,该类包含用于保存 factor
的字段.)
You can see that factor
will be captured in a closure. (You are probably already aware that behind the scenes the compiler will generate a class that contains a field to hold factor
.)
在我的机器上,它创建以下类充当闭包:
On my machine, it creates the following class to act as a closure:
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
// Fields
public int factor;
// Methods
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()一起使用.
You can see that it is creating an instance of the compiler-generated class for use with the Console.WriteLine().
您看不到的是它实际上在反编译代码中将 3
分配给 factor
的位置.要看到这一点,您必须查看IL本身(这可能是我正在使用的反编译器出现故障的原因,这已经相当老了.)
What you can't see is where it actually assigns 3
to factor
in the decompiled code. To see that, you have to look at the IL itself (this may be a failing in the decompiler I'm using, which is fairly old).
IL看起来像这样:
L_0009: ldc.i4.3
L_000a: stfld int32 ConsoleApp3.Program/<>c__DisplayClass1_0::factor
这将加载一个常数3,并将其存储在编译器生成的关闭类的 factor
字段中.
That's loading a constant value of 3 and storing it in the factor
field of the compiler-generated closure class.
这篇关于将本地功能分配给代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!