Ответ здесь:
static void Main(string[] args)
{
var list = new List<int> { 1, 2, 3 };
var x1 = new { Items = ((IEnumerable<int>)list).GetEnumerator() };
var x2 = new { Items = list.GetEnumerator() };
Console.WriteLine(ReferenceEquals(x1.Items, x1.Items));
Console.WriteLine(ReferenceEquals(x2.Items, x2.Items));
}
Вывод в консоль
True
False
А всё почему? А вот почему
public struct Enumerator : IEnumerator<T>, IEnumerator
{
// ...
}
List<T>.Enumerator
- структура. А что происходит, когда вы пытаетесь получить структуру из свойста? Правильно, копирование. Точно так же как это происходит при возврате значения из метода.
Даже вот здесь предупреждение
// CA2013 Do not pass an argument with value type 'System.Collections.Generic.List<int>.Enumerator' to 'ReferenceEquals'.
// Due to value boxing, this call to 'ReferenceEquals' will always return 'false'.
Console.WriteLine(ReferenceEquals(x2.Items, x2.Items));
Апкаст к IEnumerator
или IEnumerator<T>
позволяет забоксить структуру лишь однажды при присваивании.
А сделано это так для того чтобы при вызове .GetEnumerator()
на списке не производилась аллокация в куче. Такой энумератор на стеке отработает быстрее и не будет создавать лишней работы для сборщика мусора.
Вот этот код не сгенерирует мусора.
List<int>.Enumerator enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
Даже Dispose
этому энумератору вызывать не нужно. Так как он сидит в стеке, то будет уничтожен вместе с возвратом из метода.