#c_sharp #foreach #ienumerable
На этот вопрос уже дан ответ здесь: Работа цикла foreach, С# (1 ответ) Закрыт 2 года назад. Я реализовал простенький односвязный список сначало так : Клас, производный от интерфейса IEnumerableclass 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); }
Ответы
Ответ 1
Открываем документацию и читаем: Оператор 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 — тип значения элемента коллекции.) [Таким образом, всё происходит на этапе компиляции, рефлексия не применяется.]
Комментариев нет:
Отправить комментарий