Использование yield в C# — для чего и зачем

Сегодня рассмотрим использования ключевого слова yield в C#, разберёмся, нужно ли оно, а если да, то зачем и кому... Как пишет MSDN - если в методе или свойстве встречается yield, то данный метод или свойство является итератором.

Самый простой случай, когда использование yield очень удобно — это создание перечисления для класса. Для простоты, создадим класс User, содержащий имя, фамилию и информацию о пользователе.

public class User
 {
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Info { get; set; }
}

Наша задача состоит в том, чтобы сделать этот класс итерируемым. Для этого унаследеум класс от интерфейса IEnumerable, класс будет выглядеть следующим образом.

public class User: IEnumerable<string>
{
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Info { get; set; }

        public IEnumerator<string> GetEnumerator()
        {
            yield return FirstName;
            yield return LastName;
            yield return Info;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 }
 

Ключевое слово yield итерирует нужные нам данные. Работать это будет следёющим образом:

var user = new User {FirstName = "Андрей", LastName = "Амельченя", Info = "Дополнительная информация"};
foreach (var u in user)
{
    Console.WriteLine(u);
}

Согласитесь, полезная функция... хотя подобный функционал используется не часто, знать об этой возможности определённо следует. А вот следующий пример использования yield будет более полезный, так как может помочь с оптимизацией работы программ...

Создадим список из 10,000,000 элементов, содержащих целые числа.

public static List<int> _xList = new List<int>();

Также у нас есть метод, позволяющий получить все числа, значение которых будет больше 100

        public static IEnumerable<int> GetX()
        {
            var list = new List<int>();
            foreach (var i in _xList)
            {
                if (i > 100)
                {
                    list.Add(i);
                }
            }
            return list;
        }

Проверим, сколько памяти будет занимать данное приложение:

            for (int i = 0; i < 10000000; i++)
            {
                _xList.Add(i);
            }

            foreach (var i in GetX())
            {
                Solve(i);
            }
            Console.WriteLine((Process.GetCurrentProcess().WorkingSet64/1024) + "КB");

Метод Solve ничего не делает, он здесь для улучшения понимания кода.

Запустим приложение и увидим, сколько памяти необходимо для его работы:

Получается чуть больше 86000 килобайт.

Изменим метод GetX() используя yield:

        public static IEnumerable<int> GetX()
        {
            foreach (var i in _xList)
            {
                if (i > 100)
                {
                    yield return i;
                }
            }
        }

Результат будет таким:

Явная экономия памяти связана с тем, что не был создан дополнительный список. Также данный метод можно переписать, используя LINQ, это также даст выигрыш в памяти, но мемного меньший.

        public static IEnumerable<int> GetX()
        {
            return _xList.Where(x => x > 100);
        }

При использовании LINQ произойдёт выбор сразу всех необходимых значений, а при использовании yield новое значение будет получается уже в процессе работы финального foreach.

Подытожив скажу следующее:

yield следает применять, когда необходимо получить возможность итерировать некоторые элементы класса. Это можно делать задействовав интерфейс IEnumerable либо создав свой метод либо свойство, использующее yield. Также использование yield может помочь в оптимизиции программ. Но делать это нужно когда это действительно необходимо, ведь пример показанный выше учебный и в нем можно было вообще обойтись без метода GetX(), сразу используя foreach.

Приятного программирования.

Комментарии (2) -

Прекрасная статья! Все описано максимально простым и доступным языком. Огромное спасибо!

Спасибо! Хорошая статья с хорошими примерами!

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