IEnumerable и IEnumerator и yield примеры реализации C#

Приветствую всех, сегодня поговорим об интерфейсах IEnumerable и IEnumerator и yield. Прежде чем приступить рассмотрению примеров с интерфейсами, хотел бы показать один пример.

Представьте у нас есть класс Car, а нам нужно узнать все имеющиеся в нем модели автомобилей. Для подобного рода случая сразу хочется применить foreach

foreach(Car model in car)
Console.WriteLine(model.Type);

 

Однако это будет сделать не возможно, так как класс не реализует интерфейс IEnumerable, соответственно перечисления будет невозможно. Конечно мы можем использовать свойство Car model однако, лучше реализовать интерфейс. Что мы и сделаем! Благодаря интерфейсам IEnumerable и IEnumerator мы можем перебирать объекты в цикле foreach Для этого мы реализуем интерфейс IEnumerable в классе Car. Этот интерфейс описывает всего один метод GetEnumerator(), который возвращает интерфейс IEnumerator. В нашем случаи это может выглядеть так:

public IEnumerator GetEnumerator()
{
 return Model.GetEnumerator();
}

Теперь индексатор перенаправляет обращение по индексу к массиву Model, то метод GerEnumerator() может произвести тоже самое. И теперь наш код в самом верху заработает!

Теперь давайте рассмотрим интерфейс IEnumerator, если реализуем в нем интерфейс IEnumerator то увидим три метода.

Current(); Метод должен возвращать текущий элемент списка.

MoveNext(); изменяет счетчик или ссылку на следующий элемент списка

Reset(); Сбросить счетчик.

Практически все эти методы реализуются однотипно, и не составляют труда изменить под свои нужды. По этому я приведу пример того как это можно сделать.

T[] mass= new T[1]; //обобщенный массив.

int position = -1; //позиция перебора начинается с -1 индекса

public bool MoveNext() //изменяет счетчик или ссылку на следующий элемент списка
        {
            position++;
            return (position < mass.Length);
        }

public void Reset() //Сбросить счетчик.
        {
            position = -1;
        }
public T Current
        {
            get
            {
                try
                {
                    return mass[position];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }


object IEnumerator.Current //Метод должен возвращать текущий элемент списка.
        {
            get
            {
                return Current;
            }
        }

 

Теперь достаточно реализовать код и логику программы в методах и использовать в своих целях. Но на прямую редко кто используют интерфейс IEnumerator.

Однако так уже никто не делает, на смену пришел оператор yeild который позволяет облегчить реализацию.

public IEnumerator GetEnumerator()
{
 foreach(Car model in car)
 yield return  model; 
}

В таком варианте метода GetEnumerator() мы запускаем цикл, который перебирает все элементы списка. В нашем случаи это происходит еще в одном цикле foreach, но в зависимости от приложения может реализовано по разному. Однако важной особенностью yield является то что он после того как вернул значения, он возвращается обратно в свой метод и продолжается работа метода до завершения его. Стоит так же помнить что yield return не может использоваться внутри блоков обработки исключительных ситуаций.

Ключевое слово yield сообщает компилятору, что метод, в котором оно содержится, является блоком итератора. Для реализации поведения, определенного в блоке итератора, компилятор создает класс. В блоке итератора ключевое слово yield используется совместно с ключевым словом return для предоставления значения объекту перечислителя, например значения, возвращаемого в каждом цикле оператора foreach. Ключевое слово yield всегда используется вместе с ключевым словом break для обозначения конца итерации.
Оператор yield не может использоваться в анонимных методах.

Ниже я привел пример того как можно использовать yield в преобразовании массива в коллекцию.

  static void Main(string[] args)
        {
            int[] num = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
            foreach (var i in MyColection(num))
            {
                Console.WriteLine(i);
            }
            Console.ReadKey();
        }

        public static IEnumerable MyColection(int[] arr)
        {
            for (int i = 0; i < arr.Length; i++)
                yield return arr[i];
            yield break;
        }

 

Обновлено: 07.04.2020 — 08:58

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.