Yield oraz yield-break

Słowo kluczowe yield jest dość często wykorzystywane w c#. W przeciwieństwie do poprzednich konstrukcji, które opisywałem (np. volatile), nie trudno znaleźć zastosowanie praktycznie w projekcie. Zacznijmy  może od razu od przykładu:

foreach (int value in GetNumbers(5,7))
{
 MessageBox.Show(value.ToString());
}
// ------------------
private IEnumerable<int> GetNumbers(int start,int end)
{
  for (int i = start; i < end; i++)
      yield return i;
}

Pamiętam, że jak pierwszy raz czytałem o yield, mylące dla mnie było słowo return – wydawało mi się, że funkcja zakończy swoje działanie i zwróci pojedynczy wynik. Operator yield  służy do zwracania wartości składowych IEnumerable. Powyższy przykład zwróci liczby od start do end. Należy jednak pamiętać, że wywołując funkcję GetNumbers(5,10) generowana jest za każdym razem tylko jedna wartość np:

foreach (int value in GetNumbers(5,10))
{
 break;
}

Pętla for w GetNumbers wykona tylko jedną iteracje (zwróci wartość 5) . Gdybyśmy zwracali wynik jako tablica, od razu wszystko musiałoby zostać wygenerowane. Ma to znaczenie dla operacji czasochłonnych, zagnieżdżonych pętli oraz sytuacji gdy istnieje prawdopodobieństwo przerwania pętli na podstawie jakiegoś warunku.

Z kolei yield-break przerywa generowanie IEnumerable i nie zwraca żadnego wyniku:

private IEnumerable<int> GetNumbers(int start,int end)
{
  for (int i = start; i < end; i++)
  {
      if(i>6)
          yield break;
      yield return i;
  }
}

Zamiast yield można oczywiście napisać własny Enumerator, zaimplementować MoveNext, Current itp. Jednak w wielu przypadkach konstrukcja yield jest znacznie prostsza. Warto rozważyć yield również zamiast tworzenia listy wyników i późniejszego zwrócenia wyników jako całość. W końcu jeśli użytkownik chce od razu wszystkie wyniki, może wywołać metodę ToArray na IEnumerable.

2 thoughts on “Yield oraz yield-break”

  1. słówko return w ‘yield return’ nie jest mylący bo
    rzeczywiście powoduje wyjście z funkcji z tą różnicą że zapewnia powrót do tego samego miejsca funkcji,
    robi z funkcją coś takiego jak wywrócenie swetra na lewą stronę,
    jeżeli mamy w programie długo wykonującą się pętlę to
    dzięki niej nie musimy jej kroić tzn wyrzucać stanu pętli do pól klasy, yield zrobi to automatem
    dzięki yield można pisać sobie big pętle tj w DOSie i jednocześnie nie zagładzać wątka gui,

Leave a Reply

Your email address will not be published.