为什么在 C# 8.0 中将局部函数声明为静态

Why declare a local function static in C# 8.0

在 C# 8.0 中,Static Local Functions are announced

谁能帮我解释为什么要将局部函数声明为静态函数?

文中给出的原因:

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

但是:

  1. 我不明白为什么您要确保这一点?
  2. 将其声明为静态还有其他原因或好处吗? (可能是性能?)

文中给出的示例代码为:

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

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

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

I don't understand why would you want to ensure that?

因为它可以防止你搬起石头砸自己的脚。它强制本地函数成为不修改调用者状态的 pure function

这个returnsfalse,因为函数修改了调用者的局部变量:

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;
    }   
}

它可以防止出现意外。当然,在这些简单的例子中,好处并不是很明显,因为 "well it's obvious that Foo() modifies i",但在由多人维护且单元测试未正确覆盖的较大代码库中,这个简单的修饰符防止悲伤。

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

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

and 分别回答我问题的不同部分,所以我将它们放在一起形成已接受答案的全貌:

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

Because it prevents you from shooting yourself in the foot. It forces the local function to be a pure function that does not modify the state of the caller.

in larger codebases maintained by multiple people and not properly covered by unit tests, this simple modifier prevents grief

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

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

Capturing variables has a small additional cost as it will generate an internally used type where your captured variables are public fields

他接着举例说明了通过反射器生成的编译器代码。

所以答案2是:静态局部函数防止变量捕获。变量捕获的代价很小。因此,通过声明局部函数 static

可以稍微提高性能