Это что-то совершенно бесполезное и неправильное ...
Первый вопрос должен заключаться в том, что такое List<T>.Enumerator
... Это класс поддержки List<T>
, который реализует интерфейс IEnumerator<T>
(интерфейс, используемый для перечисления коллекции, например, foreach
). По соображениям производительности это struct
вместо class
.Быть struct
имеет предопределенный открытый конструктор без параметров (тот, который вы используете).У него даже есть конструктор internal
с одним параметром (List<T> list
), который устанавливает некоторые необходимые внутренние поля (наиболее важным является ссылка на List<>
, который его создал).Этот конструктор используется List<>.GetEnumerator()
.
Теперь, если вы сделаете то, что написали, вы создадите «неполное» Enumerator
.item.Current
будет «работать» (возвращая default(T)
), но если вы попытаетесь сделать item.MoveNext()
, вы получите NullReferenceException
.Если вы хотите IEnumerator
для «пустой» коллекции, было бы лучше сделать:
var item = Enumerable.Empty<int>().GetEnumerator();
По той причине, что List<T>.Enumerator
равно public
вместо private
или internal
... Это немного сложнее.List<T>
реализует IEnumerable<T>
и IEnumerable
, поэтому он должен иметь как минимум два метода с этими сигнатурами:
IEnumerator<T> IEnumerable<T>.GetEnumerator()
и
IEnumerator IEnumerable.GetEnumerator()
, но по соображениям производительности он их реализуеткак явная реализация (поэтому скрывает их) и реализует третий метод:
public Enumerator GetEnumerator()
, который возвращает struct Enumerator
... теперь, благодаря тому, как работает foreach
, этот третий открытый метод будетодин используется foreach
.Почему это?Потому что struct
, используемый через один из его интерфейсов (в данном случае IEnumerator<T>
или IEnumerator
), упакован (что немного замедляет его) ... но если struct
используется напрямую (через * 1050)*) метод, нет бокса, а производительность немного лучше ... Программисты Microsoft дали 110% на производительности List<>
: -)