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
factorvariable in a closure.In fact if you use a decompiler, you'll see that the following code is generated:
You can see that
factorwill 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
3tofactorin 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
factorfield of the compiler-generated closure class.