1. Funkcje zaimplementowane przez yield
Zwrot z wynosu:
Przyjrzyjmy się następującemu kodowi, który implementuje funkcję podobną do przeszukiwania tablicy z powrotem foreach do yield, wskazując, że yield return jest również używany do implementacji funkcji iteratora.
Yield break:
Patrząc na poniższy kod, na wyjściu są tylko 1 i 2, ale nie 3, co wskazuje, że iterator został zatrzymany przez yield break, więc yield break służy do zakończenia iteracji.
2. Może być używany tylko w <T><T>metodach, operatorach, get accessorach, które muszą zwracać IEnumerable, IEnumerable, IEnumerator lub IEnumerator.
3. Zasada implementacji słowa kluczowego yield
Zastąpiliśmy pętlę foreach pętlą while i odkryliśmy, że chociaż nie zaimplementowaliśmy GetEnumerator(), ani odpowiednich właściwości MoveNext() i Current odpowiadającego IEnumeratora, nadal pracowaliśmy z tymi funkcjami.
Jeśli chodzi o powód takiego stanu, możemy użyć ILSpy do dekompilacji wygenerowanego pliku exe i znaleźć przyczynę.
Ponieważ bezpośrednia dekompilacja do C# stanie się taka, jaka jest
Dlatego zdecydowaliśmy się na dekompilację do kodu IL z adnotacjami w C#, choć czytelność jest słaba, ale możemy szczegółowo zrozumieć zasady. Przyjrzyjmy się najpierw tłumaczeniu programu – podczas kompilacji automatycznie generuje się nową klasę.
Przyjrzyjmy się bliżej kodowi i EnumerableFuc() zwraca tę nową klasę.
Patrząc na implementację klasy, którą ten kod generuje automatycznie, widzimy, że dziedziczy ona <T>IEnumerable, IEnumerable, IEnumerator lub IEnumerator, i <T>powinniśmy zgadnąć, że to właśnie ta nowa klasa jest powodem, dla którego nie implementujemy odpowiednich właściwości MoveNext() i Current w IEnumeratorze, ale nadal możemy używać tych funkcji normalnie.
Przyjrzyjmy się, jak ta klasa iteruje, głównie przyjrzyjmy się funkcji MoveNext()
Każde wywołanie funkcji MoveNext() dodaje 1 do stanu, a łącznie wykonywane są 4 iteracje, z których pierwsze trzy zwracają true, a ostatnia false, co oznacza koniec iteracji. Te cztery iteracje odpowiadają stwierdzeniom w enumberableFuc(), które są podzielone na 4 części przez 3 instrukcje yield return.
Rzeczywisty proces iteracji za pomocą enumerableFuc() wygląda następująco:
1. Uruchom funkcję enumberableFuc(), aby uzyskać instancję klasy automatycznie wygenerowaną przez kod. 2. Następnie wywołaj funkcję GetEnumberator(), aby rozpocząć iterację na samej pozyskanej klasie jako iteratorze. 3. Za każdym razem, gdy uruchamiasz MoveNext(), stan wzrasta o 1, a instrukcja switch pozwala wykonywać różne części kodu za każdym razem, gdy wywołujesz MoveNext(). 4。 MoveNext() zwraca false, zakończenie. Pokazuje to również, że słowo kluczowe yield jest w rzeczywistości cukrem składniowym i ostatecznie jest to funkcja iteracyjny realizowana poprzez implementację interfejsów IEnumerable<T>, IEnumerable, <T>IEnumberator i IEnumberator.
|