Assigning local functions to delegates

后端 未结 2 1244
独厮守ぢ
独厮守ぢ 2021-01-04 07:19

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

2条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-04 08:04

    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 AssignLocalFunctionToDelegate()
    {
        int factor = 3;
        return delegate (int x) {
            return (factor * x);
        };
    }
    

    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 g__Triple0(int x)
        {
            return (this.factor * x);
        }
    }
    

    If I change AssignLocalFunctionToDelegate() to

    public static Func AssignLocalFunctionToDelegate()
    {
        int factor;
        int Triple(int x) => factor * x;
        factor = 3;
        Console.WriteLine(Triple(2));
        return Triple;
    }
    

    then the implementation becomes:

    public static Func AssignLocalFunctionToDelegate()
    {
        <>c__DisplayClass1_0 CS$<>8__locals0;
        int factor = 3;
        Console.WriteLine(CS$<>8__locals0.g__Triple0(2));
        return delegate (int x) {
            return (factor * x);
        };
    }
    

    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 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).

    The IL looks like this:

    L_0009: ldc.i4.3 
    L_000a: stfld int32 ConsoleApp3.Program/<>c__DisplayClass1_0::factor
    

    That's loading a constant value of 3 and storing it in the factor field of the compiler-generated closure class.

提交回复
热议问题