Como ninguém aqui citou diretamente o ECMA-334 :
10.4.4.10 Para declarações
Verificação de atribuição definida para uma declaração for do formulário:
for (for-initializer; for-condition; for-iterator) embedded-statement
é feito como se a declaração estivesse escrita:
{
for-initializer;
while (for-condition) {
embedded-statement;
LLoop: for-iterator;
}
}
Mais adiante na especificação,
12.16.6.3 Instanciação de variáveis locais
Uma variável local é considerada instanciada quando a execução entra no escopo da variável.
[Exemplo: por exemplo, quando o método a seguir é chamado, a variável local x
é instanciada e inicializada três vezes - uma vez para cada iteração do loop.
static void F() {
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
...
}
}
No entanto, mover a declaração de x
fora do loop resulta em uma única instanciação de x
:
static void F() {
int x;
for (int i = 0; i < 3; i++) {
x = i * 2 + 1;
...
}
}
exemplo final]
Quando não capturada, não há como observar exatamente com que frequência uma variável local é instanciada - como as vidas úteis das instanciações são disjuntas, é possível para cada instanciação simplesmente usar o mesmo local de armazenamento. No entanto, quando uma função anônima captura uma variável local, os efeitos da instanciação se tornam aparentes.
[Exemplo: o exemplo
using System;
delegate void D();
class Test{
static D[] F() {
D[] result = new D[3];
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
result[i] = () => { Console.WriteLine(x); };
}
return result;
}
static void Main() {
foreach (D d in F()) d();
}
}
produz a saída:
1
3
5
No entanto, quando a declaração de x
é movida para fora do loop:
static D[] F() {
D[] result = new D[3];
int x;
for (int i = 0; i < 3; i++) {
x = i * 2 + 1;
result[i] = () => { Console.WriteLine(x); };
}
return result;
}
a saída é:
5
5
5
Observe que o compilador tem permissão (mas não é obrigatório) para otimizar as três instanciações em uma única instância de delegação (§11.7.2).
Se um loop for declarar uma variável de iteração, essa variável em si será considerada declarada fora do loop. [Exemplo: portanto, se o exemplo for alterado para capturar a própria variável de iteração:
static D[] F() {
D[] result = new D[3];
for (int i = 0; i < 3; i++) {
result[i] = () => { Console.WriteLine(i); };
}
return result;
}
apenas uma instância da variável de iteração é capturada, o que produz a saída:
3
3
3
exemplo final]
Sim, acho que deve ser mencionado que em C ++ esse problema não ocorre porque você pode escolher se a variável é capturada por valor ou por referência (consulte: Captura Lambda ).