将本地功能分配给代表 [英] Assigning local functions to delegates

查看:53
本文介绍了将本地功能分配给代表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这篇关于将本地功能分配给代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆