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