List<T>.GetEnumerator()
zwraca wartość typu zmienny (List<T>.Enumerator
). Przechowujesz tę wartość w anonimowym typie.
Teraz rzućmy okiem na to, co to robi:
while (x.TempList.MoveNext())
{
// Ignore this
}
to odpowiednik:
while (true)
{
var tmp = x.TempList;
var result = tmp.MoveNext();
if (!result)
{
break;
}
// Original loop body
}
Teraz pamiętać, co mamy wywołanie MoveNext()
on - kopii wartości który jest w typie anonimowym. Nie możesz zmienić wartości w anonimowym typie - wszystko, co masz, to właściwość, którą możesz wywołać, co da ci kopię wartości.
W przypadku zmiany kodu do:
var x = new { TempList = (IEnumerable<int>) new List<int> { 1, 3, 6, 9 }.GetEnumerator() };
... wtedy będziesz skończyć uzyskanie odniesienie w anonimowym typu. Odniesienie do pola zawierającego zmienną wartość. Kiedy zadzwonisz pod numer MoveNext()
, wartość wewnątrz tego pola zostanie zmutowana, więc zrobi to, co chcesz.
Do analizy w bardzo podobnej sytuacji (ponownie przy użyciu List<T>.GetEnumerator()
) patrz my 2010 blog post "Iterate, damn you!".
Patrzę na to i mam problem z ustaleniem, który element jest tutaj typem wartości, dla którego rozróżnienie kopii/odniesienia faktycznie ma znaczenie. –
Nie dostałem go, jak to działa dobrze, jeśli rzucimy go na '' IEnumerable ''? @JonSkeet można wyjaśnić więcej w prostych słowach –
@ EhsanSajjad: Gdy typem kompilacji 'TempList' jest' IEnumerable ', dostęp do niego po prostu kopiuje odniesienie. Działanie zgodnie z tym odniesieniem zmutuje wartość pudełkową, a następnym razem, gdy skopiujesz odniesienie, nadal będzie ona odnosić się do tej samej wartości pudełkowej, więc widzisz zmianę. Porównaj to z kopiowaniem wartości typu wartości i mutowaniem tej kopii - gdy * następnie * skopiujesz oryginalną wartość, nie zobaczysz poprzedniej zmiany. –