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
}
It does in fact work!
My question is: why does this work? What is going on here?
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:
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 holdfactor
.)On my machine, it creates the following class to act as a closure:
If I change
AssignLocalFunctionToDelegate()
tothen the implementation becomes:
You can see that it is creating an instance of the compiler-generated class for use with the Console.WriteLine().
What you can't see is where it actually assigns
3
tofactor
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).The IL looks like this:
That's loading a constant value of 3 and storing it in the
factor
field of the compiler-generated closure class.