Jednak dokumentacja MSDN wspomina o tym, ale go nie wyjaśnia. To zły sposób na dokuczanie głodnemu wiedzy deweloperowi.
Phil
3
Zwrot wydajności eliminuje potrzebę tworzenia listy kopii zapasowych, co oznacza, że nie trzeba kodować czegoś takiego jak MyList.Add(...)po prostu zrobić yield return .... Jeśli musisz przedwcześnie wyjść z pętli i zwrócić wirtualną listę kopii zapasowych, której używaszyield break;
The Muffin Man
Odpowiedzi:
529
Określa, że iterator dobiegł końca. Można myśleć yield breakjako returnoświadczenia, które nie zwraca wartości.
Na przykład, jeśli zdefiniujesz funkcję jako iterator, jej treść może wyglądać następująco:
for(int i =0; i <5; i++){yieldreturn i;}Console.Out.WriteLine("You will see me");
Zauważ, że po zakończeniu wszystkich cykli, ostatnia linia zostanie wykonana i zobaczysz komunikat w aplikacji na konsolę.
Lub tak z yield break:
int i =0;while(true){if(i <5){yieldreturn i;}else{// note that i++ will not be executed after thisyieldbreak;}
i++;}Console.Out.WriteLine("Won't see me");
W takim przypadku ostatnia instrukcja nigdy nie jest wykonywana, ponieważ wcześniej opuściliśmy funkcję.
Czy może to być po prostu breakzamiast yield breakw powyższym przykładzie? Kompilator na to nie narzeka.
orad
85
@ lub zwykły breakw tym przypadku zatrzymałby pętlę, ale nie przerwałby wykonywania metody, dlatego ostatni wiersz zostałby wykonany, a tekst „Nie zobaczyłby mnie” byłby rzeczywiście widoczny.
Damir Zekić
5
@Damir Zekić Czy mógłbyś również dodać do swojej odpowiedzi, dlaczego powinieneś preferować podział rentowności zamiast zwrotu i jakie są różnice między nimi?
Bruno Costa
11
@ DamirZekić zwraca wartość null, a podział zysków nie jest taki sam. Jeśli zwrócisz null, możesz NullReferenceExceptionuzyskać moduł wyliczający IEnumerable, podczas gdy przy podziale wydajności nie będziesz (istnieje instancja bez elementów).
Bruno Costa
6
@BrunoCosta Próba regularnych zwrotów w tej samej metodzie powoduje błąd kompilatora. Za pomocą yield return xalertów kompilatora chcesz, aby ta metoda była cukrem syntaktycznym do tworzenia Enumeratorobiektu. Ten moduł wyliczający ma metodę MoveNext()i właściwość Current. MoveNext () wykonuje metodę aż do yield returninstrukcji i zamienia tę wartość na Current. Przy następnym wywołaniu MoveNext wykonywanie będzie kontynuowane od tego momentu. yield breakustawia Current na null, sygnalizując koniec tego modułu wyliczającego, tak aby foreach (var x in myEnum())koniec się zakończył.
Wolfzoon,
57
Kończy blok iteratora (np. Mówi, że w IEnumerable nie ma więcej elementów).
z [+1] - chociaż naukowo nie ma iteratorów w .NET. tylko wyliczacze (w jednym kierunku, do przodu)
Shaun Wilson
@Shaun Wilson, ale za pomocą yieldsłowa kluczowego możesz iterować kolekcję w obu kierunkach, ponadto możesz wziąć każdy kolejny element kolekcji nie z rzędu
monstr
@monstr możesz iterować kolekcję w dowolny sposób i nie musisz yieldtego robić. nie mówię, że się mylisz, rozumiem, co sugerujesz; ale naukowo w .NET nie ma iteratorów, tylko enumeratory (jeden kierunek, do przodu) - w przeciwieństwie do stdc ++ nie ma „ogólnej struktury iteratora” zdefiniowanej w CTS / CLR. LINQ pomaga zlikwidować lukę za pomocą metod rozszerzenia, które wykorzystują, yield returna także metod wywołania zwrotnego , ale są to metody rozszerzenia pierwszej klasy, a nie iteratory pierwszej klasy. wynikowa IEnumerablesama w sobie nie może iterować w żadnym innym kierunku niż przekierowanie do dzwoniącego.
Shaun Wilson,
29
Mówi iteratorowi, że osiągnął koniec.
Jako przykład:
publicinterfaceINode{IEnumerable<Node>GetChildren();}publicclassNodeWithTenChildren:INode{privateNode[] m_children =newNode[10];publicIEnumerable<Node>GetChildren(){for(int n =0; n <10;++n ){yieldreturn m_children[ n ];}}}publicclassNodeWithNoChildren:INode{publicIEnumerable<Node>GetChildren(){yieldbreak;}}
yieldw zasadzie sprawia, że IEnumerable<T>metoda zachowuje się podobnie do zaplanowanego wątku kooperacyjnego (w przeciwieństwie do zapobiegawczego).
yield returnprzypomina wątek wywołujący funkcję „harmonogramu” lub „uśpienia”, aby zrezygnować z kontroli nad procesorem. Podobnie jak wątek, IEnumerable<T>metoda natychmiast odzyskuje kontrolę w punkcie natychmiastowym, przy czym wszystkie zmienne lokalne mają takie same wartości, jak przed rezygnacją z kontroli.
yield break jest jak nić sięgająca końca swojej funkcji i kończąca się.
Ludzie mówią o „maszynie stanu”, ale maszyna stanu to tak naprawdę „wątek”. Wątek ma pewien stan (tj. Wartości zmiennych lokalnych) i za każdym razem, gdy jest planowany, podejmuje pewne działania w celu osiągnięcia nowego stanu. Kluczową kwestią yieldjest to, że w przeciwieństwie do wątków systemu operacyjnego, do których jesteśmy przyzwyczajeni, kod, który go używa, jest zamrożony w czasie, aż iteracja zostanie ręcznie zaawansowana lub zakończona.
yield breakOświadczenie powoduje wyliczanie przestać. W efekcie yield breakwykonuje wyliczenie bez zwracania żadnych dodatkowych elementów.
Rozważ, że istnieją dwa sposoby, aby metoda iteracyjna mogła zatrzymać iterację. W jednym przypadku logika metody może naturalnie wyjść z metody po zwróceniu wszystkich elementów. Oto przykład:
IEnumerable<uint>FindPrimes(uint startAt,uint maxCount){for(var i =0UL; i < maxCount; i++){
startAt =NextPrime(startAt);yieldreturn startAt;}Debug.WriteLine("All the primes were found.");}
W powyższym przykładzie metoda iteratora w naturalny sposób przestanie maxCountdziałać po znalezieniu liczb pierwszych.
yield breakStwierdzenie jest kolejnym sposobem na iterator do zaprzestania wyliczanie. Jest to sposób na wczesne wyjście z wyliczenia. Oto ta sama metoda, jak powyżej. Tym razem metoda ma limit czasu, który metoda może wykonać.
IEnumerable<uint>FindPrimes(uint startAt,uint maxCount,int maxMinutes){var sw =System.Diagnostics.Stopwatch.StartNew();for(var i =0UL; i < maxCount; i++){
startAt =NextPrime(startAt);yieldreturn startAt;if(sw.Elapsed.TotalMinutes> maxMinutes)yieldbreak;}Debug.WriteLine("All the primes were found.");}
Zwróć uwagę na połączenie z yield break. W efekcie wychodzi z wyliczenia wcześniej.
Zauważ też, że yield breakdziała inaczej niż zwykła break. W powyższym przykładzie yield breakkończy metodę bez wykonywania wywołania Debug.WriteLine(..).
public static IEnumerable <int> Zakres (int min, int max)
{
podczas gdy (prawda)
{
jeśli (min> = maks.)
{
spadek wydajności;
}
zwrot wydajności min ++;
}
}
i wyjaśnienie, że jeśli yield breakinstrukcja zostanie trafiona w metodzie, wykonanie tej metody kończy się bez powrotu. Są sytuacje czasowe, w których nie chcesz dawać żadnych rezultatów, możesz użyć podziału zysków.
Cóż, są skomplikowane tylko wtedy, gdy zależy ci na kodzie, w który zostały wkompilowane. Kod, który ich używa, jest dość prosty.
Robert Rossney
@Robert, właśnie to miałem na myśli, dlatego zaktualizowałem odpowiedź, dodając twój komentarz
Tony Lee
-2
Słowo kluczowe fed jest używane razem ze słowem kluczowym return, aby zapewnić wartość dla obiektu wyliczającego. Zwrot wydajności określa zwracaną wartość lub wartości. Po osiągnięciu instrukcji zwrotu z zysku bieżąca lokalizacja jest zapisywana. Wykonanie jest ponownie uruchamiane z tej lokalizacji przy następnym wywołaniu iteratora.
Należy zauważyć, że zmienna licznika w tym przykładzie jest zmienną lokalną. Po drugiej iteracji, która zwraca wartość 2, trzecia iteracja rozpoczyna się od miejsca, w którym poprzednio opuściła, zachowując poprzednią wartość zmiennej lokalnej o nazwie counter, która wynosiła 2.
Nie sądzę, że yield returnfaktycznie obsługuje zwracanie wielu wartości. Może nie o to ci chodziło, ale tak to czytam.
Sam
Sam - metoda SampleNumbers z wielu wypowiedzi obie wydajność robi w rzeczywistości pracy, wartość iteratora jest zwracane niezwłocznie i wykonanie jest wznowione, gdy następna wartość jest wymagana. Widziałem, jak ludzie kończą taką metodę „podziałem zysków”, ale jest to niepotrzebne. Dotknięcie końca metody kończy także iterator
Loren Paulsen
powodem, dla którego jest to kiepski przykład, yield breakjest to, że nie zawiera on foreachmodułu wyliczającego na poziomie języka, takiego jak a - przy użyciu modułu wyliczającego yield breakzapewnia rzeczywistą wartość. ten przykład wygląda jak rozwinięta pętla. prawie nigdy nie zobaczysz tego kodu w prawdziwym świecie (wszyscy możemy myśleć o niektórych przypadkach brzegowych, oczywiście) również, nie ma tutaj „iteratora”. „blok iteratora” nie może wykraczać poza metodę ze względu na specyfikację języka. to, co faktycznie jest zwracane, jest „wyliczalne”, patrz także: stackoverflow.com/questions/742497/…
MyList.Add(...)
po prostu zrobićyield return ...
. Jeśli musisz przedwcześnie wyjść z pętli i zwrócić wirtualną listę kopii zapasowych, której używaszyield break;
Odpowiedzi:
Określa, że iterator dobiegł końca. Można myśleć
yield break
jakoreturn
oświadczenia, które nie zwraca wartości.Na przykład, jeśli zdefiniujesz funkcję jako iterator, jej treść może wyglądać następująco:
Zauważ, że po zakończeniu wszystkich cykli, ostatnia linia zostanie wykonana i zobaczysz komunikat w aplikacji na konsolę.
Lub tak z
yield break
:W takim przypadku ostatnia instrukcja nigdy nie jest wykonywana, ponieważ wcześniej opuściliśmy funkcję.
źródło
break
zamiastyield break
w powyższym przykładzie? Kompilator na to nie narzeka.break
w tym przypadku zatrzymałby pętlę, ale nie przerwałby wykonywania metody, dlatego ostatni wiersz zostałby wykonany, a tekst „Nie zobaczyłby mnie” byłby rzeczywiście widoczny.NullReferenceException
uzyskać moduł wyliczający IEnumerable, podczas gdy przy podziale wydajności nie będziesz (istnieje instancja bez elementów).yield return x
alertów kompilatora chcesz, aby ta metoda była cukrem syntaktycznym do tworzeniaEnumerator
obiektu. Ten moduł wyliczający ma metodęMoveNext()
i właściwośćCurrent
. MoveNext () wykonuje metodę aż doyield return
instrukcji i zamienia tę wartość naCurrent
. Przy następnym wywołaniu MoveNext wykonywanie będzie kontynuowane od tego momentu.yield break
ustawia Current na null, sygnalizując koniec tego modułu wyliczającego, tak abyforeach (var x in myEnum())
koniec się zakończył.Kończy blok iteratora (np. Mówi, że w IEnumerable nie ma więcej elementów).
źródło
yield
słowa kluczowego możesz iterować kolekcję w obu kierunkach, ponadto możesz wziąć każdy kolejny element kolekcji nie z rzęduyield
tego robić. nie mówię, że się mylisz, rozumiem, co sugerujesz; ale naukowo w .NET nie ma iteratorów, tylko enumeratory (jeden kierunek, do przodu) - w przeciwieństwie do stdc ++ nie ma „ogólnej struktury iteratora” zdefiniowanej w CTS / CLR. LINQ pomaga zlikwidować lukę za pomocą metod rozszerzenia, które wykorzystują,yield return
a także metod wywołania zwrotnego , ale są to metody rozszerzenia pierwszej klasy, a nie iteratory pierwszej klasy. wynikowaIEnumerable
sama w sobie nie może iterować w żadnym innym kierunku niż przekierowanie do dzwoniącego.Mówi iteratorowi, że osiągnął koniec.
Jako przykład:
źródło
yield
w zasadzie sprawia, żeIEnumerable<T>
metoda zachowuje się podobnie do zaplanowanego wątku kooperacyjnego (w przeciwieństwie do zapobiegawczego).yield return
przypomina wątek wywołujący funkcję „harmonogramu” lub „uśpienia”, aby zrezygnować z kontroli nad procesorem. Podobnie jak wątek,IEnumerable<T>
metoda natychmiast odzyskuje kontrolę w punkcie natychmiastowym, przy czym wszystkie zmienne lokalne mają takie same wartości, jak przed rezygnacją z kontroli.yield break
jest jak nić sięgająca końca swojej funkcji i kończąca się.Ludzie mówią o „maszynie stanu”, ale maszyna stanu to tak naprawdę „wątek”. Wątek ma pewien stan (tj. Wartości zmiennych lokalnych) i za każdym razem, gdy jest planowany, podejmuje pewne działania w celu osiągnięcia nowego stanu. Kluczową kwestią
yield
jest to, że w przeciwieństwie do wątków systemu operacyjnego, do których jesteśmy przyzwyczajeni, kod, który go używa, jest zamrożony w czasie, aż iteracja zostanie ręcznie zaawansowana lub zakończona.źródło
Cały temat bloków iteratora jest dobrze omówiony w tym darmowym przykładowym rozdziale książki Jona Skeeta C # in Depth .
źródło
yield break
Oświadczenie powoduje wyliczanie przestać. W efekcieyield break
wykonuje wyliczenie bez zwracania żadnych dodatkowych elementów.Rozważ, że istnieją dwa sposoby, aby metoda iteracyjna mogła zatrzymać iterację. W jednym przypadku logika metody może naturalnie wyjść z metody po zwróceniu wszystkich elementów. Oto przykład:
W powyższym przykładzie metoda iteratora w naturalny sposób przestanie
maxCount
działać po znalezieniu liczb pierwszych.yield break
Stwierdzenie jest kolejnym sposobem na iterator do zaprzestania wyliczanie. Jest to sposób na wczesne wyjście z wyliczenia. Oto ta sama metoda, jak powyżej. Tym razem metoda ma limit czasu, który metoda może wykonać.Zwróć uwagę na połączenie z
yield break
. W efekcie wychodzi z wyliczenia wcześniej.Zauważ też, że
yield break
działa inaczej niż zwykłabreak
. W powyższym przykładzieyield break
kończy metodę bez wykonywania wywołaniaDebug.WriteLine(..)
.źródło
Tutaj http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ jest bardzo dobrym przykładem:
i wyjaśnienie, że jeśli
yield break
instrukcja zostanie trafiona w metodzie, wykonanie tej metody kończy się bez powrotu. Są sytuacje czasowe, w których nie chcesz dawać żadnych rezultatów, możesz użyć podziału zysków.źródło
podział zysków jest tylko sposobem na powiedzenie zwrotu po raz ostatni i nie zwraca żadnej wartości
na przykład
źródło
Jeśli to, co rozumiesz przez „to, co naprawdę robi podział zysków”, to „jak to działa” - zobacz blog Raymonda Chena, aby uzyskać szczegółowe informacje https://devblogs.microsoft.com/oldnewthing/20080812-00/?p=21273
Iteratory C # generują bardzo skomplikowany kod.
źródło
Słowo kluczowe fed jest używane razem ze słowem kluczowym return, aby zapewnić wartość dla obiektu wyliczającego. Zwrot wydajności określa zwracaną wartość lub wartości. Po osiągnięciu instrukcji zwrotu z zysku bieżąca lokalizacja jest zapisywana. Wykonanie jest ponownie uruchamiane z tej lokalizacji przy następnym wywołaniu iteratora.
Aby wyjaśnić znaczenie na przykładzie:
Wartości zwracane podczas iteracji to: 0, 2, 5.
Należy zauważyć, że zmienna licznika w tym przykładzie jest zmienną lokalną. Po drugiej iteracji, która zwraca wartość 2, trzecia iteracja rozpoczyna się od miejsca, w którym poprzednio opuściła, zachowując poprzednią wartość zmiennej lokalnej o nazwie counter, która wynosiła 2.
źródło
yield break
znaczyyield return
faktycznie obsługuje zwracanie wielu wartości. Może nie o to ci chodziło, ale tak to czytam.yield break
jest to, że nie zawiera onforeach
modułu wyliczającego na poziomie języka, takiego jak a - przy użyciu modułu wyliczającegoyield break
zapewnia rzeczywistą wartość. ten przykład wygląda jak rozwinięta pętla. prawie nigdy nie zobaczysz tego kodu w prawdziwym świecie (wszyscy możemy myśleć o niektórych przypadkach brzegowych, oczywiście) również, nie ma tutaj „iteratora”. „blok iteratora” nie może wykraczać poza metodę ze względu na specyfikację języka. to, co faktycznie jest zwracane, jest „wyliczalne”, patrz także: stackoverflow.com/questions/742497/…