使用延迟执行保留超出范围的堆栈变量

Joh*_*son 1 .net c# stack multithreading

我承认这个问题显示了很多关于堆栈和堆栈的误解.希望我在这里问一个合适的问题.

在C#中,如何为代码处理堆栈帧和局部变量,如下所示.让这些案例变得有趣的是,StartTasks中的变量j和StartTasks2中的变量i都被Task使用,这些变量可能在这些变量不再在范围内之后运行,并且在堆栈帧之后运行它们通常会被弹出堆.

此外,在什么条件下,像j这样不断被"重新创建"的局部变量在超出范围后获得一个全新的内存槽,就像StartTask中发生的那样,该局部变量存在于何处(即StartTasks的堆栈框架,这意味着框架无法删除,或其他地方)?

void StartTasks() {
    int i = 0;
    while ( i < 10000 ) {
        int j = i;
        Task.Run( () => ExecuteThis( j ) ); // eac
    }
}

void StartTasks2() {
    int i = 0;
    while ( i < 10000 ) {
        Task.Run( () => ExecuteThis( i ) ); // eac
    }
}


void BigBoss() {
    StartTasks();
    StartTasks2();
    NowMakeMoreCalls();
}
Run Code Online (Sandbox Code Playgroud)

Sim*_*ead 5

它们被提升为编译器生成的类的一部分.

对您提供的内容进行简单的反编译可以得到一些答案:

[CompilerGenerated]
private sealed class <>c__DisplayClass5
{
  public int i;
  public Program <>__this;

  public <>__DisplayClass5()
  {
    base.<>ctor();
  }

  public void <CStartTasks2>b__3()
  {
    this.<>4__this.ExecuteThis(this.i);
  }
}
Run Code Online (Sandbox Code Playgroud)

编译器生成此类并将对调用类的引用传递给它.它还将关闭的变量存储为实例字段.

所以,回答这个问题......它们没有在堆栈上分配.它们形成在编译时定义的对象,并在运行时实例化.