No encerramento, o que desencadeia uma nova instância da variável capturada?

Estou lendo o Jon Skeet'sC # em profundidade.

Na página 156, ele tem um exemplo, a Listagem 5.13 "Capturando Instanciações de Variáveis ​​Múltiplas com Vários Delegados".

List<ThreadStart> list = new List<ThreadStart>();

for(int index=0; index < 5; index++;)
{
    int counter = index*10;
    list.Add(delegate
          {
              Console.WriteLine(counter);
              counter++;
          }
        );
}

foreach(ThreadStart t in list)
{
    t();
}

list[0]();
list[0]();
list[0]();

list[1]();

Na explicação após esta listagem, ele diz que "cada uma das instâncias delegadas capturou uma variável diferente neste caso".

Eu entendo isso bem o suficiente porque eu entendo que cada vez que você fecha uma variável o compilador gera IL que o encapsula em uma nova classe feita especificamente para permitir que aquela variável seja capturada (essencialmente tornando-a um tipo de referência para que o valor esteja se referindo to não é destruído com o quadro de pilha do escopo atualmente em execução).

Mas então ele fala sobre o que teria acontecido se tivéssemos capturadoindex diretamente em vez de criar ocounter variável - "todos os delegados teriam compartilhado a mesma variável".

Isso eu não entendo. Não éindex no mesmo âmbito quecounter? Por que o compilador não criaria também uma nova instância deindex para cada delegado?

Nota: Eu acho que descobri como eu digitei essa questão, mas deixarei a questão aqui para a posteridade. Eu acho que a resposta é queindex está realmente em um escopo diferente comocounter. O índice é essencialmente declarado "fora" do loop for ... é a mesma variável todas as vezes.

Dando uma olhada no IL gerado por umfor loop, prova que as variáveis ​​são declaradas fora do loop (length ei foram variáveis ​​declaradas nofor declaração de loop).

.locals init (
    [0] int32 length,
    [1] int32 i,
    [2] bool CSEu entendo isso bem o suficiente porque eu entendo que cada vez que você fecha uma variável o compilador gera IL que o encapsula em uma nova classe feita especificamente para permitir que aquela variável seja capturada (essencialmente tornando-a um tipo de referência para que o valor esteja se referindo to não é destruído com o quadro de pilha do escopo atualmente em execução).0000
)

IL_0000: nop
IL_0001: ldc.i4.s 10
IL_0003: stloc.0
IL_0004: ldc.i4.0
IL_0005: stloc.1
IL_0006: br.s IL_001b
// loop start (head: IL_001b)
    IL_0008: nop
    IL_0009: ldloca.s i
    IL_000b: call instance string [mscorlib]System.Int32::ToString()
    IL_0010: call void [mscorlib]System.Console::WriteLine(string)
    IL_0015: nop
    IL_0016: nop
    IL_0017: ldloc.1
    IL_0018: ldc.i4.1
    IL_0019: add
    IL_001a: stloc.1

    IL_001b: ldloc.1
    IL_001c: ldloc.0
    IL_001d: clt
    IL_001f: stloc.2
    IL_0020: ldloc.2
    IL_0021: brtrue.s IL_0008
// end loop

Uma coisa que eu acho que o livro poderia ter feito melhor com relação a este assunto é realmente explicar o que o compilador está fazendo, porque toda essa "mágica" faz sentido se você entender que o compilador está envolvendo a variável fechada em uma nova classe.

Por favor corrija quaisquer equívocos ou mal entendidos que eu possa ter. Além disso, sinta-se à vontade para elaborar e / ou adicionar à minha explicação.

questionAnswers(2)

yourAnswerToTheQuestion