Где общий список‹› реализует сброс?

когда я перехожу к определению List‹>, я вижу, что у него есть общедоступная структура Enumerator, которая реализует интерфейсы IEnumerator<T>, IDisposable и IEnumerator.

IEnumerator должен принудительно реализовать Reset — помимо Current и MoveNext. Однако реализованы только Current и MoveNext. Как это может быть?
Где я могу найти Reset() для List‹>?

var list = new List<int>();
list.Add(23);
list.Add(44);
var Enumerator = list.GetEnumerator();
while (Enumerator.MoveNext())
{
    Console.WriteLine(Enumerator.Current);
}
Enumerator.

И когда я пробую это в коде, нет Reset():
Хорошо - я пытался показать скриншот, но они не позволяют мне.
Но копирование выше кода не показывает Reset-Method после Точка-оператор (.) перечислителя.

Кто-нибудь знает и прольет свет на это?

Я вижу, что он вызывает сброс IEnumerator, который является частью mscorlib.

var list = new List<int>();
list.Add(23);
list.Add(44);
var Enumerator = list.GetEnumerator();
Enumerator.MoveNext();
Enumerator.MoveNext();
Console.WriteLine(Enumerator.Current);
((IEnumerator<int>)Enumerator).Reset();
Enumerator.MoveNext();

И все же, поскольку IEnumerator — это интерфейс, как он может вызывать код?
Reset() в IEnumerator должен быть просто определением, а реализация должна быть оставлена ​​тому, кто использует интерфейс.
Но каким-то образом здесь фактическая функциональность обеспечивается только определение интерфейса, который должен быть реализован. Нигде я не вижу фактической реализации - и эту часть я не понимаю.


person Andi Truman    schedule 10.08.2015    source источник


Ответы (2)


Он явно реализован, как показано в документации, как IEnumerator.Current. Другими словами, вы можете вызывать метод только для значения с типом времени компиляции IEnumerator.

Итак, вы можете использовать:

// Casing changed to be more conventional
var enumerator = list.GetEnumerator();
((IEnumerator)enumerator).Reset();

Однако это все равно упаковало бы значение (поскольку List<T>.Enumerator является структурой), что сделало бы его бессмысленным. Непонятно, интересует ли вас просто явное отсутствие метода Reset, но в целом я бы настоятельно не советовал вам не полагаться на IEnumerator.Reset - он очень часто не реализован, и, по моему мнению, не должен. это было частью интерфейса с самого начала...

person Jon Skeet    schedule 10.08.2015
comment
Спасибо, и да - я споткнулся о очевидное отсутствие Reset() - person Andi Truman; 10.08.2015
comment
Привет, мне пришлось отредактировать свой исходный пост, потому что форматирование комментариев ограничено. - person Andi Truman; 10.08.2015
comment
@AndiTruman: Вы задали совершенно другой вопрос во второй части сейчас - я предлагаю вам снова удалить его из вопроса, поскольку в основном это то, как работают интерфейсы, которые, как я подозреваю, рассматриваются в другом месте ... - person Jon Skeet; 10.08.2015

Вы думаете, что используете интерфейс IEnumerator‹>, но это не так. Вывод типа становится лучше вас, тип вашей переменной Enumerator на самом деле List.Enumerator‹>, тип структуры. Используйте интерфейс, и у вас не будет проблем:

    IEnumerator<int> Enumerator = list.GetEnumerator();
    while (Enumerator.MoveNext()) {
        Console.WriteLine(Enumerator.Current);
    }
    Enumerator.Reset();  // Fine

Он не работает с List.Enumerator‹>, потому что Microsoft намеренно скрыла реализацию метода Reset(), сделав его закрытым. Обратите внимание, как ведут себя итераторы для других классов коллекций, таких как Dictionary и HashSet.

Это могло бы использовать объяснение. IEnumerator инкапсулирует итератор прямого действия и является фундаментом, на котором был построен дом Linq. Метод Reset() представляет собой проблему, которая больше не является строго прямой. Вы перемещаете итератор назад. На практике вы обнаружите, что во многих случаях попытка вызова Reset() приводит к NotImplementedException. Не проблема для Листа, легко вернуться. Большая проблема для Linq.

IEnumerator должен быть разработан без метода Reset(). Но это не было выбором дизайнеров .NET, это было сделано до 1996 года, задолго до того, как кто-либо начал работать над .NET. Итераторы были существующей концепцией в автоматизации COM. Модель расширения для Visual Basic версии 4 заменила 16-разрядную модель VBX.

Чрезвычайно популярный, почти любой язык выполнения в Windows реализует его. И все еще очень активно используется в программах .NET. В большинстве случаев искусно спрятан, и невозможно сказать, что вы используете его, например, когда вы помещаете веб-браузер в свой пользовательский интерфейс. Разработчики .NET также были вынуждены реализовать его, чтобы попытаться заставить программистов перейти на .NET. Также источник очень проблемного интерфейса ICloneable.

person Hans Passant    schedule 10.08.2015
comment
Спасибо вам обоим. Таким образом, реализация универсального IEnumerator все еще существует и также доступна — просто скрыта. - person Andi Truman; 11.08.2015