List<T>.GetEnumerator()
restituisce un tipo di valore mutabile (List<T>.Enumerator
). Stai memorizzando quel valore nel tipo anonimo.
Ora, diamo un'occhiata a ciò che fa:
while (x.TempList.MoveNext())
{
// Ignore this
}
Questo è equivalente a:
while (true)
{
var tmp = x.TempList;
var result = tmp.MoveNext();
if (!result)
{
break;
}
// Original loop body
}
Ora notare quello che stiamo chiamando MoveNext()
sul - la copia del valore che è nel tipo anonimo. Non puoi in realtà cambiare il valore nel tipo anonimo: tutto ciò che hai è una proprietà che puoi chiamare, che ti darà una copia del valore.
Se si modifica il codice per:
var x = new { TempList = (IEnumerable<int>) new List<int> { 1, 3, 6, 9 }.GetEnumerator() };
... Allora ti finisce per ottenere un di riferimento nel tipo anonimo. Un riferimento a una scatola contenente il valore mutabile. Quando chiami MoveNext()
su quel riferimento, il valore all'interno della casella verrà modificato, quindi farà ciò che desideri.
Per analisi su una situazione molto simile (sempre utilizzando List<T>.GetEnumerator()
), vedere my 2010 blog post "Iterate, damn you!".
fonte
2015-07-23 15:08:28
Sto guardando questo e ho difficoltà a capire quale elemento qui è un tipo di valore per il quale la distinzione copia/riferimento effettivamente fa la differenza. –
non ce l'ho, come funziona bene se lo lanciamo in '' IEnumerable '' ?? @JonSkeet puoi spiegarlo di più con parole semplici –
@EhsanSajjad: Quando il tipo in fase di compilazione di 'TempList' è' IEnumerable ', l'accesso ad esso copia semplicemente un riferimento. Agire su quel riferimento muterà il valore in box, e la volta successiva che copi un riferimento si riferirà comunque allo stesso valore in box, quindi vedrai la modifica. Confrontalo con il valore del tipo di valore e modificando la copia - quando * successivo * copi il valore originale, non vedrai la modifica precedente. –