Poiché nessuno qui citava direttamente l' ECMA-334 :
10.4.4.10 Per le dichiarazioni
Verifica assegnazione definitiva per una dichiarazione for del modulo:
for (for-initializer; for-condition; for-iterator) embedded-statement
viene fatto come se la dichiarazione fosse scritta:
{
for-initializer;
while (for-condition) {
embedded-statement;
LLoop: for-iterator;
}
}
Più avanti nelle specifiche,
12.16.6.3 Istantanea di variabili locali
Una variabile locale viene considerata come un'istanza quando l'esecuzione entra nell'ambito della variabile.
[Esempio: ad esempio, quando viene invocato il seguente metodo, la variabile locale x
viene istanziata e inizializzata tre volte, una volta per ogni iterazione del ciclo.
static void F() {
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
...
}
}
Tuttavia, spostando la dichiarazione di x
fuori del ciclo si ottiene una singola istanza di x
:
static void F() {
int x;
for (int i = 0; i < 3; i++) {
x = i * 2 + 1;
...
}
}
fine esempio]
Quando non viene acquisito, non è possibile osservare con esattezza la frequenza con cui viene istanziata una variabile locale, poiché la durata delle istanze è disgiunta, per ciascuna istanza è possibile utilizzare semplicemente la stessa posizione di archiviazione. Tuttavia, quando una funzione anonima acquisisce una variabile locale, gli effetti dell'istanza diventano evidenti.
[Esempio: l'esempio
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();
}
}
produce l'output:
1
3
5
Tuttavia, quando la dichiarazione di x
viene spostata all'esterno del ciclo:
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;
}
l'output è:
5
5
5
Si noti che al compilatore è consentito (ma non necessario) di ottimizzare le tre istanze in una singola istanza delegato (§11.7.2).
Se un ciclo for dichiara una variabile di iterazione, quella stessa variabile viene considerata dichiarata al di fuori del ciclo. [Esempio: Pertanto, se l'esempio viene modificato per acquisire la variabile di iterazione stessa:
static D[] F() {
D[] result = new D[3];
for (int i = 0; i < 3; i++) {
result[i] = () => { Console.WriteLine(i); };
}
return result;
}
viene catturata solo un'istanza della variabile di iterazione, che produce l'output:
3
3
3
fine esempio]
Oh sì, immagino che si dovrebbe menzionare che in C ++ questo problema non si verifica perché puoi scegliere se la variabile viene catturata per valore o per riferimento (vedi: Lambda capture ).