2012-03-01 17 views
5

Próbuję lepiej zrozumieć słowo "yield" i myślę, że mam wystarczająco dobre zrozumienie tego, więc przeprowadziłem testy, ale byłem zaskoczony wynikami.Zrozumienie słowa kluczowego yield i LINQ

Jeśli uruchomić poniższy kod otrzymuję następujący wynik, który pokazuje, że pętle w całym zakresie nie tylko do numeru 4.

public void DoIt() 
    { 
     Console.WriteLine("Method Call"); 
     var results = GetData(Enumerable.Range(1, 10)); 
     Console.WriteLine("LINQ"); 
     var filtered = results.Where(x => x == 4); 
     Console.WriteLine("Start result loop"); 
     foreach (var item in filtered) 
     { 
       Console.WriteLine("Item is " + item); 
     } 
    } 

    private IEnumerable<int> GetData(IEnumerable<int> Input) 
    { 
     foreach (int item in Input) 
     { 
      if (item % 2 == 0) 
      { 
       Console.WriteLine("Found " + item); 
       yield return item; 
      } 
     } 
    } 

wyjściowa:

Method Call 
LINQ 
Start result loop 
Found 2 
Found 4 
Item is 4 
Found 6 
Found 8 
Found 10 

Jeśli Uruchomiłem poniższy kod, który pokazuje, że dociera tylko do 4, a następnie zatrzymuje się.

public void DoIt() 
    { 
     Console.WriteLine("Method Call"); 
     var results = GetData(Enumerable.Range(1, 10)); 
     Console.WriteLine("Start result loop"); 
     foreach (var item in results) 
     { 
      if (item == 4) 
      { 
       Console.WriteLine("Item is " + item); 
       break; 
      } 
     } 
    } 

    private IEnumerable<int> GetData(IEnumerable<int> Input) 
    { 
     foreach (int item in Input) 
     { 
      if (item % 2 == 0) 
      { 
       Console.WriteLine("Found " + item); 
       yield return item; 
      } 
     } 
    } 

wyjściowa:

Method Call 
Start result loop 
Found 2 
Found 4 
Item is 4 

Chyba nie jestem understading coś ale wygląda jakby LINQ robi przeciwieństwo tego, czego od niego oczekujesz? Chociaż LINQ wykorzystywał również wydajność i odraczanie wykonania, i oczekiwałbym, że wyniki z drugiego zestawu kodów będą takie same dla pierwszego zestawu kodu.

+0

'Gdzie" filtruje wyniki, nie zatrzymuje wyników zwracanych, gdy element spełnia predykat. Z drugiej strony twoja ręczna pętla 'foreach' zrywa się, gdy predykat jest spełniony ... –

Odpowiedz

12

Korzysta z odroczonej realizacji. LINQ Where sprawdza wszystkie elementy wejścia, które można przeliczyć, nie zatrzymuje się, gdy dotrze do pierwszego znalezionego elementu. To właśnie robi First.

Twój pierwszy przykład powróci tak samo jak drugi przykład, jeśli zmienisz Where na First lub jeśli usuniesz break z drugiego przykładu.

2

Myślę, że masz podstawową logikę źle, nie LINQ. Twój pierwszy przykład musi powtórzyć cały zakres, ponieważ warunek where musi znaleźć wszystkie wartości równe 4, a nie tylko pierwszą wartość, która jest równa 4.

Powiązane problemy