Widziałem tę składnię w MSDN: yield break
ale nie wiem, co ona robi. Czy ktoś wie?
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;
Widziałem tę składnię w MSDN: yield break
ale nie wiem, co ona robi. Czy ktoś wie?
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
jako return
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:
for (int i = 0; i < 5; i++)
{
yield return 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)
{
yield return i;
}
else
{
// note that i++ will not be executed after this
yield break;
}
i++;
}
Console.Out.WriteLine("Won't see me");
W takim przypadku ostatnia instrukcja nigdy nie jest wykonywana, ponieważ wcześniej opuściliśmy funkcję.
break
zamiast yield 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 tworzenia Enumerator
obiektu. Ten moduł wyliczający ma metodę MoveNext()
i właściwość Current
. MoveNext () wykonuje metodę aż do yield return
instrukcji i zamienia tę wartość na Current
. 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 aby foreach (var x in myEnum())
koniec się zakończył.
Kończy blok iteratora (np. Mówi, że w IEnumerable nie ma więcej elementów).
yield
słowa kluczowego możesz iterować kolekcję w obu kierunkach, ponadto możesz wziąć każdy kolejny element kolekcji nie z rzędu
yield
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. wynikowa IEnumerable
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:
public interface INode
{
IEnumerable<Node> GetChildren();
}
public class NodeWithTenChildren : INode
{
private Node[] m_children = new Node[10];
public IEnumerable<Node> GetChildren()
{
for( int n = 0; n < 10; ++n )
{
yield return m_children[ n ];
}
}
}
public class NodeWithNoChildren : INode
{
public IEnumerable<Node> GetChildren()
{
yield break;
}
}
yield
w zasadzie sprawia, że IEnumerable<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.
Cały temat bloków iteratora jest dobrze omówiony w tym darmowym przykładowym rozdziale książki Jona Skeeta C # in Depth .
yield break
Oświadczenie powoduje wyliczanie przestać. W efekcie yield 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:
IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
for (var i = 0UL; i < maxCount; i++)
{
startAt = NextPrime(startAt);
yield return startAt;
}
Debug.WriteLine("All the primes were found.");
}
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ć.
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);
yield return startAt;
if (sw.Elapsed.TotalMinutes > maxMinutes)
yield break;
}
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 break
działa inaczej niż zwykła break
. W powyższym przykładzie yield break
kończy metodę bez wykonywania wywołania Debug.WriteLine(..)
.
Tutaj http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ jest bardzo dobrym przykładem:
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 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.
podział zysków jest tylko sposobem na powiedzenie zwrotu po raz ostatni i nie zwraca żadnej wartości
na przykład
// returns 1,2,3,4,5
IEnumerable<int> CountToFive()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
yield break;
yield return 6;
yield return 7;
yield return 8;
yield return 9;
}
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.
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:
public IEnumerable<int> SampleNumbers() { int counter = 0; yield return counter; counter = counter + 2; yield return counter; counter = counter + 3; yield return counter ; }
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.
yield break
znaczy
yield 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 on foreach
modułu wyliczającego na poziomie języka, takiego jak a - przy użyciu modułu wyliczającego yield 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/…