2009-01-31 14 views
28

Powiel możliwe:
What does “yield break;” do in C#?Jaka jest korzyść z przełomu w plonach?

Czy ktoś może zobaczyć zastosowanie do „break wydajność” oświadczenie, że nie można było inaczej osiągnąć stosując „przerwy” lub „powrót”.

To stwierdzenie wydaje się całkowicie bezużyteczne. Co więcej, bez tego stwierdzenia, zwrot "zwrotu rentowności X" mógłby zostać uproszczony, aby "uzyskać X", który jest znacznie bardziej czytelny.

Czego mi brakuje?

Odpowiedz

7

Obniżenie plonów określa, że ​​metoda powinna zatrzymać zatrzymywanie zwracanych wyników. "Zwrot" sam w sobie nie byłby wystarczająco dobry, a nawet mógłby doprowadzić do błędu, ponieważ typ powrotu metody musi być IEnumerable.

Nie jestem pewien, dlaczego potrzebne jest słowo kluczowe return. Domyślam się, że pomaga to w wyraźniejszym sformułowaniu intencji oświadczenia.

Jeśli jesteś zainteresowany tym artykule wyjaśniono, co wydajność robi za kulisami

Behind the scenes of the C# yield keyword

+0

To nie tak, jak czytam zachowanie - "przerwa w plonach" anuluje całą metodę, nie zwracając nic. Możesz mieć "zwrot z inwestycji (ed)" 10 000 sztuk, ale jeśli "przerwa w plonach" zostanie trafiona w ramach tej samej metody, otrzymasz 0 pozycji łącznie. –

+1

@Dave: Nie sądzę ... jak leniwa ewaluacja zadziała w bloku iteratora? – chakrit

+4

@Dave, nie, przerwa w plonach powstrzymuje więcej rzeczy przed zwrotem, ale nie (i nie może) anulować, które zostały już zwrócone. – configurator

0

Trzeba mieć rozróżnienie między powrocie IEnumerable implementację, która już istnieje (być może masz zamiar zwróci Lista) i anonimowy iterator.

Nie można po prostu użyć zwrotu lub przerwy, ponieważ są to poprawne słowa kluczowe, które można wykorzystać do innych celów. Nie możesz również użyć wydajności na własnej, ponieważ musisz mieć sposób na określenie, czy zwracasz element w wyliczeniu, czy też kończąc wyliczanie, stąd potrzeba zwrotu plonu i złamania plonu.

4

Niedozwolone jest używanie instrukcji return w bloku iteratora. Co więcej, instrukcja break mogłaby służyć podwójnemu celowi w bloku iteratora, gdyby mogła wpłynąć na iterację: może zostać użyta do przerwania pętli lub przełączenia i może zostać użyta do przełamania cała iteracja.

yield return i yield break i są to dwa słowa kluczowe same w sobie i oba wydają się niezbędne.

1

return Instrukcja służy do zwracania wartości z funkcji.

Jeśli masz iterator takiego:

public IEnumerable<int> IteratorOverInt() { } 

oświadczenie return w powyższej funkcji musiałby wrócić wypełniony IEnumerable<int>.

public IEnumerable<int> IteratorOverInt() { 
    return new List<int> { 1, 2, 3, 4 }; 
} 

ale jeśli pracujesz na iterator, która będzie używana yield return, więc kod może wyglądać następująco:

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

Więc yield return jest zwrócenie int natomiast podpis metoda wymaga IEnumerable<int>

Co zrobi w tym przypadku oświadczenie return? Zwróć wyniki, które przekraczają wydajność? Łącząc cokolwiek z plonami? return nie ma większego sensu w powyższym przypadku.

W ten sposób potrzebujemy drogi do return, która ma sens w bloku iteratora, dlatego istnieje yield break.

Oczywiście można to zrobić za pomocą break, ale w jaki sposób można wyjść z treści funkcji, jeśli masz więcej kodu, który zostanie wykonany? Zawiń wszystko w skomplikowanym bloku if-else? Powiedziałbym, że po prostu lepsze byłoby yield break.

51

Aby podać przykład kodu, powiedz, że chcesz napisać iterator, który nic nie zwraca, jeśli źródło ma wartość null lub jest puste.

public IEnumerable<T> EnumerateThroughNull<T>(IEnumerable<T> source) 
{ 
    if (source == null) 
     yield break; 

    foreach (T item in source) 
     yield return item; 
} 

Bez przerwy w produkcji niemożliwe staje się zwrócenie pustego zestawu wewnątrz iteratora.

+0

@Cameron: dzięki za ten przykładowy kod, pomógł mi z problemem miałem! Sława! –

+1

break yield zwraca puste wyliczalne ... zasadniczo (w twoim przypadku) to samo, co 'return new T [0]', ale bez tworzenia pustej tablicy. – Will

+2

Cóż, moglibyśmy po prostu uczynić instrukcję if uruchomioną tylko wtedy, gdy source! = Null, ale punkt podjął – Casebash

4

Przerwa w produkcji i przerwa to zupełnie inne rzeczy! Spójrz

for(int i = 0; i < 10; ++i) { 
    if(i > 5) { break; } 
    yield return i; 
} 

for(int v = 2710; v < 2714; v+=2) { 
    yield return v; 
} 

for(int s = 16; s < 147; ++s) { 
    if(s == 27) { yield break; } 
    else if(s > 17) { yield return s; } 
} 

wyjściowy będzie IEnumerable z tych wartości: 0, 1, 2, 3, 4, 5, 2710, 2712, 18, 19, 20, 21, 22, 23, 24, 25, 26

Oto pewna metoda, która nie przynosi niczego użytecznego, ale pokazuje, że można połączyć przełamanie plonu i rozbić na tę samą metodę, i robią dwie różne rzeczy! Przerwa właśnie zrywa się z pętli, przerwa w produkcji kończy się całkowicie.

Domyślam się, że powód powrotu nie jest używany, ponieważ nie zwracasz samego siebie w metodzie IElicznik. Poza tym, czy nie sądzisz, że przełom w wydatkach jest wyraźniejszy niż powrót, w przypadku takiej iteracyjnej sytuacji? Robię to osobiście.

+0

lol oh whoops, którego nie chciałem, aby to zrobić, naprawię to. –

Powiązane problemy