Для чего используется ключевое слово yield в C #?

В вопросе Как я могу раскрыть только фрагмент IList <> один из ответов содержал следующий фрагмент кода:

IEnumerable FilteredList()
{
    foreach(object item in FullList)
    {
        if(IsItemInPartialList(item))
            yield return item;
    }
}

Что здесь делает ключевое слово yield? Я видел ссылки в нескольких местах, и еще один вопрос, но я не совсем понял, что он на самом деле делает. Я привык думать о доходности в том смысле, что один поток уступает другому, но здесь это не актуально.

748
задан Tvde1 15 July 2019 в 07:33
поделиться

8 ответов

yield ключевое слово на самом деле делает довольно много здесь.

функция возвращает объект, который реализует эти IEnumerable<object> интерфейс. Если функция вызова запускается foreach луг по этому объекту, функция вызвана снова, пока это не "уступает". Это - синтаксический сахар, представленный в [1 116] C# 2.0. В более ранних версиях необходимо было создать собственное IEnumerable и IEnumerator объекты сделать материал как это.

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

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}

, Когда Вы ступите через пример, Вы найдете первый вызов к Integers() возвраты 1. Вторые возвраты вызова 2 и строка yield return 1 не выполняются снова.

Вот реальный пример:

public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)
{
    using (var connection = CreateConnection())
    {
        using (var command = CreateCommand(CommandType.Text, sql, connection, parms))
        {
            command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return make(reader);
                }
            }
        }
    }
}
663
ответ дан daaawx 15 July 2019 в 07:33
поделиться

Это производит счетную последовательность. То, что это делает, на самом деле создает локальную последовательность IEnumerable и возвращает его как результат метода

4
ответ дан aku 15 July 2019 в 07:33
поделиться

Это - очень простой и легкий способ создать счетное для Вашего объекта. Компилятор создает класс, который обертывает Ваш метод, и это реализует, в этом случае, IEnumerable< объект>. Без ключевого слова урожая необходимо было бы создать объект, который реализует IEnumerable< объект>.

6
ответ дан Will 15 July 2019 в 07:33
поделиться

Недавно Raymond Chen также выполнил интересный ряд статей о ключевом слове урожая.

, В то время как это номинально используется для того, чтобы легко реализовать шаблон итератора, но может быть обобщено в конечный автомат. Никакой смысл в заключении в кавычки Raymond, последняя часть также связывается с другим использованием (но примером в блоге Entin является хороший ESP, показывая, как записать асинхронный безопасный код).

130
ответ дан skovenborg 15 July 2019 в 07:33
поделиться

Это пытается ввести некоторое Совершенство Ruby:)
Понятие: Это - некоторый демонстрационный код Ruby, который распечатывает каждый элемент массива

 rubyArray = [1,2,3,4,5,6,7,8,9,10]
    rubyArray.each{|x| 
        puts x   # do whatever with x
    }

каждая реализация метода Массива урожаи управление вызывающей стороне ('помещает x') с каждый элемент массива, аккуратно представленного как x. Вызывающая сторона может тогда сделать то, что это должно сделать с x.

Однако .Net не идет полностью сюда.. C#, кажется, связал урожай с IEnumerable, способом вынуждая Вас записать цикл foreach в вызывающей стороне, как замечено в ответе Mendelt. Немного менее изящный.

//calling code
foreach(int i in obCustomClass.Each())
{
    Console.WriteLine(i.ToString());
}

// CustomClass implementation
private int[] data = {1,2,3,4,5,6,7,8,9,10};
public IEnumerable<int> Each()
{
   for(int iLooper=0; iLooper<data.Length; ++iLooper)
        yield return data[iLooper]; 
}
-2
ответ дан Gishu 15 July 2019 в 07:33
поделиться

Интуитивно, ключевое слово возвращает значение из функции, не оставляя его, т.е. в Вашем примере кода это возвращает ток item значение и затем возобновляет цикл. Более официально это используется компилятором для генерации кода для итератор . Итераторы являются функциями тот возврат IEnumerable объекты. MSDN имеет несколько статьи о них.

31
ответ дан Konrad Rudolph 15 July 2019 в 07:33
поделиться

Повторение. Это создает конечный автомат "под покрытиями", который помнит, где Вы были на каждом дополнительном цикле функции, и берет оттуда.

350
ответ дан Joel Coehoorn 15 July 2019 в 07:33
поделиться

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

Пример: Не использование Урожая т.е. Никакого Ленивого Выполнения.

        public static IEnumerable<int> CreateCollectionWithList()
        {
            var list =  new List<int>();
            list.Add(10);
            list.Add(0);
            list.Add(1);
            list.Add(2);
            list.Add(20);

            return list;
        }

Пример: использование Урожая т.е. Ленивого Выполнения.

    public static IEnumerable<int> CreateCollectionWithYield()
    {
        yield return 10;
        for (int i = 0; i < 3; i++) 
        {
            yield return i;
        }

        yield return 20;
    }

Теперь, когда я называю оба метода.

var listItems = CreateCollectionWithList();
var yieldedItems = CreateCollectionWithYield();

Вы заметите, что listItems будет иметь 5 объектами в нем (парение Ваша мышь на listItems при отладке). Принимая во внимание, что yieldItems будет просто иметь ссылку на метод а не объекты. Это означает, что не выполнило процесс получения объектов в методе. Очень эффективное способ получить данные только при необходимости. Фактическая реализация урожая может замеченный в ORM как Платформа Объекта и NHibernate и т.д.

0
ответ дан 22 November 2019 в 21:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: