Why declare a local function static in C# 8.0

fou*_*der 5 .net c# static c#-8.0 local-functions

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;
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*ter 5

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

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.

This returns false, because the function modifies local variables of its caller:

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

    void Foo()
    {
        i = 21;
    }   
}
Run Code Online (Sandbox Code Playgroud)

And this doesn't, because it doesn't even compile:

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

    static void Foo()
    {
        i = 21;
    }   
}
Run Code Online (Sandbox Code Playgroud)

It prevents surprises. Of course in these simple examples the benefit isn't immediately clear, because "well it's obvious that Foo() modifies i", but in larger codebases maintained by multiple people and not properly covered by unit tests, this simple modifier prevents grief.


Gyö*_*zeg 5

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

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

    int Add() => x + y;
}
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)


fou*_*der 3

CodeCaster 的这个答案和Gy\xc3\xb6rgy K\xc5\x91szeg 的单独答案分别回答了我问题的不同部分,因此我将它们放在一起以形成可接受答案的完整图片:

\n

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

\n
\n

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

\n

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

\n
\n

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

\n

对于我的问题的第 2 部分,@Gy\xc3\xb6rgy K\xc5\x91szeg 说:

\n
\n

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

\n
\n

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

\n

所以答案 2 是:静态局部函数阻止变量捕获。变量捕获的成本很小。因此,通过将局部函数声明为静态可以稍微提高性能

\n