Язык программирования C#9 и платформа .NET5. Страница 177
Вспомните средство локальных функций версии C# 7, представленное в главе 4; локальные функции — это закрытые функции, которые определены внутри других функций. За счет перемещения
yield returnMoveNext()Приведите метод к следующему виду:
public IEnumerator GetEnumerator(){ // Это исключение сгенерируется немедленно throw new Exception("This will get called"); return ActualImplementation(); // Локальная функция и фактическая реализация IEnumerator IEnumerator ActualImplementation() { foreach (Car c in carArray) { yield return c; } }}
Ниже показан тестовый код:
Console.WriteLine("***** Fun with the Yield Keyword *****\n");Garage carLot = new Garage();try{ // На этот раз возникает ошибка var carEnumerator = carLot.GetEnumerator();}catch (Exception e){ Console.WriteLine($"Exception occurred on GetEnumerator");}Console.ReadLine();В результате такого обновления метода
GetEnumerator()MoveNext()Построение именованного итератора
Также интересно отметить, что ключевое слово
yieldIEnumerableIEnumeratorGaragepublic IEnumerable GetTheCars(bool returnReversed){ // Выполнить проверку на предмет ошибок return ActualImplementation(); IEnumerable ActualImplementation() { // Возвратить элементы в обратном порядке. if (returnReversed) { for (int i = carArray.Length; i != 0; i--) { yield return carArray[i - 1]; } } else { // Возвратить элементы в том порядке, в каком они размещены в массиве. foreach (Car c in carArray) { yield return c; } } }}Обратите внимание, что новый метод позволяет вызывающему коду получать элементы в прямом, а также в обратном порядке, если во входном параметре указано значение
trueGetTheCars()throw newGetEnumerator()Console.WriteLine("***** Fun with the Yield Keyword *****\n");Garage carLot = new Garage();// Получить элементы, используя GetEnumerator().foreach (Car c in carLot){ Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);}Console.WriteLine();<b>// Получить элементы (в обратном порядке!)</b><b>// с применением именованного итератора.</b>foreach (Car c in carLot.GetTheCars(true)){ Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);}Console.ReadLine();Наверняка вы согласитесь с тем, что именованные итераторы являются удобными конструкциями, поскольку они позволяют определять в единственном специальном контейнере множество способов запрашивания возвращаемого набора.
Итак, в завершение темы построения перечислимых объектов запомните: для того, чтобы специальные типы могли работать с ключевым словом
foreachGetEnumerator()IEnumerableyield return