19

In C# 8.0, Static Local Functions are announced

Can anyone help enlighten me as to why you would want to declare a local function as static?

The reason given in in the article:

to ensure that local function doesn't capture (reference) any variables from the enclosing scope

But:

  1. I don't understand why would you want to ensure that?
  2. Is there any other reason or benefits to declare it static? (performance maybe?)

The example code given in the article is:

int M()
{
    int y = 5;
    int x = 7;
    return Add(x, y);

    static int Add(int left, int right) => left + right;
}
4

4 回答 4

21

我不明白你为什么要确保这一点?

因为它可以防止你射中自己的脚。它强制本地函数是一个不修改调用者状态的纯函数。

这会返回false,因为函数修改了调用者的局部变量:

public bool Is42()
{
    int i = 42;     
    Foo();      
    return i == 42;

    void Foo()
    {
        i = 21;
    }   
}

这没有,因为它甚至没有编译:

public bool Is42()
{
    int i = 42;     
    Foo();      
    return i == 42;

    static void Foo()
    {
        i = 21;
    }   
}

它可以防止意外。当然,在这些简单的例子中,好处并不是很明显,因为Foo()修改很明显i,但是在由多人维护并且没有被单元测试正确覆盖的大型代码库中,这个简单的修饰符可以防止悲伤。

于 2019-11-07T10:11:54.127 回答
5

捕获变量会产生少量额外成本,因为它会生成一个内部使用的类型,其中捕获的变量是公共字段。考虑一个稍微修改的例子:

int M()
{
    int y = 5;
    int x = 7;
    return Add();

    int Add() => x + y;
}

它实际上会转化为这样的东西:

int M()
{
    int y = 5;
    int x = 7;
    var capturedVars = new <>c__DisplayClass0_0 { x = x, y = y };
    return <M>g__Add|0_0(ref capturedVars);
}

[CompilerGenerated]
private struct <>c__DisplayClass0_0
{
    public int x;
    public int y;
}

[CompilerGenerated]
internal static int <M>g__Add|0_0(ref <>c__DisplayClass0_0 class_Ref1) => 
    (class_Ref1.x + class_Ref1.y);
于 2019-11-07T10:18:31.740 回答
3

CodeCaster的这个答案和György Kőszeg 的这个单独的答案分别回答了我问题的不同部分,所以我将它们放在一起形成接受答案的全貌:

对于我的问题的第 1 部分,@CodeCaster 说:

因为它可以防止你射中自己的脚。它强制本地函数成为一个不修改调用者状态的纯函数。

在由多人维护且没有被单元测试正确覆盖的大型代码库中,这个简单的修饰符可以防止悲伤

所以答案 1 是:静态局部函数确保可靠的调用方方法状态。

对于我的问题的第 2 部分,@György Kőszeg 说:

捕获变量会产生少量额外成本,因为它会生成一个内部使用的类型,其中捕获的变量是公共字段

他接着给出了一个通过反射器生成的编译器代码的例子。

所以答案 2 是:静态局部函数防止变量捕获。变量捕获的成本很低。因此,通过声明局部函数为静态的,性能会有所提升

于 2019-11-08T09:46:05.770 回答
1

我认为这只是为了确保正确使用本地函数中使用的变量,如文档所述。在大而复杂的方法中,如果局部函数中存在同名变量,它可以防止意外使用封闭范围变量。

于 2019-11-07T09:49:08.657 回答