Для чего используется ключевое слово yield в C #? - PullRequest
740 голосов
/ 02 сентября 2008

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

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

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

Ответы [ 16 ]

12 голосов
/ 16 апреля 2018

Если я правильно понимаю, вот как я бы сформулировал это с точки зрения функции, реализующей IEnumerable с yield.

  • Вот один.
  • Позвоните еще раз, если вам нужен другой.
  • Я буду помнить то, что я тебе уже дал.
  • Я буду знать только, смогу ли я дать вам еще один, когда вы снова позвоните.
10 голосов
/ 15 января 2013

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

В JavaScript такая же концепция называется Генераторы.

6 голосов
/ 02 сентября 2008

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

4 голосов
/ 02 сентября 2008

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

2 голосов
/ 01 мая 2016

Эта ссылка имеет простой пример

Здесь приведены еще более простые примеры

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

Обратите внимание, что возвращаемая доходность не вернется из метода. Вы можете даже поставить WriteLine после yield return

Выше приведено IEnumerable 4 целых 4,4,4,4

Здесь с WriteLine. Добавьте 4 в список, напечатайте abc, затем добавьте 4 в список, затем завершите метод и, таким образом, действительно вернитесь из метода (как только метод завершится, как это будет происходить с процедурой без возврата). Но это будет иметь значение, IEnumerable список int с, которое будет возвращено при завершении.

public static IEnumerable<int> testYieldb()
{
    yield return 4;
    console.WriteLine("abc");
    yield return 4;
}

Обратите внимание, что когда вы используете yield, то, что вы возвращаете, не того же типа, что и функция. Это тип элемента в списке IEnumerable.

Вы используете yield с типом возврата метода как IEnumerable. Если тип возвращаемого метода - int или List<int> и вы используете yield, он не скомпилируется. Вы можете использовать IEnumerable метод возврата типа без yield, но, возможно, вы не можете использовать yield без IEnumerable метода возврата метода.

И чтобы заставить его исполниться, нужно вызвать его особым образом.

static void Main(string[] args)
{
    testA();
    Console.Write("try again. the above won't execute any of the function!\n");

    foreach (var x in testA()) { }


    Console.ReadLine();
}



// static List<int> testA()
static IEnumerable<int> testA()
{
    Console.WriteLine("asdfa");
    yield return 1;
    Console.WriteLine("asdf");
}
0 голосов
/ 02 сентября 2008

Он пытается внести немного Рубинового Блага :) 1001 * Концепция: Это пример кода Ruby, который распечатывает каждый элемент массива

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

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

Однако .Net здесь не доходит до конца ... Кажется, C # совпал с yield в IEnumerable, что вынуждает вас написать цикл вызова в вызывающей программе, как видно из ответа Менделя. Немного менее элегантно.

//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]; 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...