Страницы

Поиск по вопросам

понедельник, 8 апреля 2019 г.

IEnumerable и оператор foreach() [дубликат]

На данный вопрос уже ответили: Работа цикла foreach, С# 1 ответ Я реализовал простенький односвязный список сначало так : Клас, производный от интерфейса IEnumerable
class MyList : IEnumerable { public Goods head; public Goods tail; //add,remove и так далее public IEnumerator GetEnumerator() { Goods curr = head; while (curr != null) { yield return curr.Item; curr = curr.Next; } }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
Затем его переписал его так, что бы он не был производным от интерфейса IEnumerable
class MyList { public Goods head; public Goods tail; //add,remove и так далее public IEnumerator GetEnumerator() { Goods curr = head; while (curr != null) { yield return curr.Item; curr = curr.Next; } } }
На MDSN написано :
The foreach statement repeats a group of embedded statements for each element in an array or an object collection that implements the IEnumerable or IEnumerable interface.
Второй класс не является производным от IEnumerable. Каким образом я тогда могу спокойно по нему пройтись оператором foreach()?
MyList myList = new MyList(); myList.Add(10); myList.Add(20); foreach(var c in myList) { Console.WriteLine(c); }


Ответ

Открываем документацию и читаем:
Оператор foreach выполняет оператор или блок операторов для каждого элемента в экземпляре типа, который реализует интерфейс System.Collections.IEnumerable или System.Collections.Generic.IEnumerable. Оператор foreach не ограничивается этими типами. Он может применяться к экземпляру любого типа, который удовлетворяет следующим условиям: включает открытый метод GetEnumerator без параметров со следующим типом возвращаемого значения: класс, структура или тип интерфейса; тип возвращаемого значения метода GetEnumerator должен содержать открытое свойство Current и открытый метод MoveNext без параметров с типом возвращаемого значения Boolean

Таким образом, достаточно просто наличия подходящего метода GetEnumerator

Спецификация уточняет, что вот такой foreach
foreach (V v in x) embedded_statement
на этапе компиляции раскрывается в
{ E e = ((C)(x)).GetEnumerator(); try { while (e.MoveNext()) { V v = (V)(T)e.Current; embedded_statement } } finally { ... // Dispose e } }
(C — тип коллекции, E — тип энумератора, V — тип значения элемента коллекции.) [Таким образом, всё происходит на этапе компиляции, рефлексия не применяется.]

Комментариев нет:

Отправить комментарий