Po prawie 4 latach doświadczeń, nie widziałem kodu gdzie wydajność jest używane słowo kluczowe. Czy ktoś może mi pokazać praktyczne użycie (wraz z objaśnieniem) tego słowa kluczowego, a jeśli tak, to czy nie istnieją inne sposoby łatwiejszego wypełnienia tego, co może zrobić?
76
yield
można ogólnie wykorzystać.Odpowiedzi:
Wydajność
Słowo
yield
kluczowe skutecznie tworzy leniwe wyliczenie ponad elementami kolekcji, które mogą być znacznie bardziej wydajne. Na przykład, jeśli twojaforeach
pętla dokonuje iteracji tylko pierwszych 5 elementów z 1 miliona przedmiotów, to wszystko toyield
zwraca, a najpierw nie zbudowałeś kolekcji 1 miliona przedmiotów. Podobnie będzie chciał skorzystaćyield
zIEnumerable<T>
wartości zwracanych własnymi scenariuszami programowania, aby osiągnąć te same korzyści.Przykład wydajności uzyskanej w określonym scenariuszu
Nie jest to metoda iteracyjna, potencjalnie nieefektywne użycie dużej kolekcji
(kolekcja pośrednia jest zbudowana z dużą ilością przedmiotów)
Wersja Iterator, wydajna
(nie jest budowana kolekcja pośrednia)
Uprość niektóre scenariusze programowania
W innym przypadku ułatwia to programowanie sortowania i scalania list, ponieważ po prostu
yield
elementy z powrotem w pożądanej kolejności zamiast sortować je do kolekcji pośredniej i zamieniać je tam. Istnieje wiele takich scenariuszy.Jednym z przykładów jest połączenie dwóch list:
Ta metoda daje jedną ciągłą listę elementów, co skutecznie łączy się bez pośredniej kolekcji.
Więcej informacji
yield
Kluczowe może być stosowany tylko w kontekście metody iteracyjnej (o typ zwrotnegoIEnumerable
,IEnumerator
,IEnumerable<T>
, iIEnumerator<T>
.) I nie jest szczególny stosunekforeach
. Iteratory to specjalne metody. Dokumentacja wydajności MSDN i dokumentacja iteratora zawiera wiele interesujących informacji i objaśnień pojęć. Pamiętaj, aby skorelować go zforeach
kluczowych czytając o nim też uzupełnić swoją wiedzę iteratorów.Aby dowiedzieć się, w jaki sposób iteratory osiągają swoją wydajność, sekret znajduje się w kodzie IL wygenerowanym przez kompilator C #. IL wygenerowana dla metody iteracyjnej różni się drastycznie od generowanej dla zwykłej metody (nie iteracyjnej). Ten artykuł (co naprawdę generuje słowo kluczowe Yield?) Zawiera tego rodzaju informacje.
źródło
database.Customers.Count()
wyliczenie nie obejmuje całego wyliczenia klientów, co wymaga bardziej wydajnego kodu, aby przejść przez każdy element?Jakiś czas temu miałem praktyczny przykład, załóżmy, że masz taką sytuację:
Obiekt przycisku nie zna swojej pozycji w kolekcji. To samo ograniczenie dotyczy
Dictionary<T>
innych typów kolekcji.Oto moje rozwiązanie za pomocą
yield
słowa kluczowego:I tak to wykorzystuję:
Nie muszę tworzyć
for
pętli w mojej kolekcji, aby znaleźć indeks. Mój przycisk ma identyfikator, który służy również jako indeksIndexerList<T>
, więc unikniesz zbędnych identyfikatorów lub indeksów - to lubię! Indeks / identyfikator może być dowolną liczbą.źródło
Praktyczny przykład można znaleźć tutaj:
http://www.ytechie.com/2009/02/using-c-yield-for-readability-and-performance.html
Istnieje wiele zalet używania wydajności w stosunku do standardowego kodu:
Jednak, jak powiedział Jan_V (po prostu pobij mnie o kilka sekund :-) możesz żyć bez niego, ponieważ wewnętrznie kompilator wygeneruje kod prawie identyczny w obu przypadkach.
źródło
Oto przykład:
https://bitbucket.org/ant512/workingweek/src/a745d02ba16f/source/WorkingWeek/Week.cs#cl-158
Klasa wykonuje obliczenia daty na podstawie tygodnia roboczego. Mogę powiedzieć instancji klasy, że Bob pracuje od 9:30 do 17:30 każdego tygodnia z godzinną przerwą na lunch o 12:30. Dzięki tej wiedzy funkcja AscendingShift () da obiekty robocze zmiany między podanymi datami. Aby wymienić wszystkie zmiany robocze Boba między 1 stycznia a 1 lutego tego roku, możesz użyć tego w następujący sposób:
Klasa tak naprawdę nie przechodzi przez kolekcję. Jednak przesunięcia między dwiema datami można traktować jako zbiór.
yield
Operator umożliwia iteracyjne nad tej wyobrażonej kolekcję bez tworzenia samej kolekcji.źródło
Mam małą warstwę danych db, która ma
command
klasę, w której ustawiasz tekst polecenia SQL, typ polecenia i zwracasz IEnumerable z „parametrów polecenia”.Zasadniczo chodzi o to, aby wpisywać polecenia CLR zamiast ręcznie wypełniać
SqlCommand
właściwości i parametry przez cały czas.Jest więc funkcja, która wygląda następująco:
Klasa, która dziedziczy tę
command
klasę, ma właściwościAge
iName
.Następnie możesz nowy
command
obiekt wypełnić jego właściwości i przekazać go dodb
interfejsu, który faktycznie wywołuje polecenie.Podsumowując, praca z poleceniami SQL jest naprawdę łatwa.
źródło
Chociaż przypadek scalenia został już uwzględniony w zaakceptowanej odpowiedzi, pozwól, że pokażę Ci metodę rozszerzania parametrów łączenia z wydajnością ™:
Używam tego do budowania pakietów protokołu sieciowego:
Na
MarkChecksum
przykład metoda wygląda następująco. I mayield
też:Należy jednak zachować ostrożność, stosując metody agregujące, takie jak Sum () w metodzie wyliczania, ponieważ uruchamiają one osobny proces wyliczania.
źródło
Repozytorium przykładowe Elastic Search .NET ma świetny przykład użycia
yield return
do podzielenia kolekcji na wiele kolekcji o określonym rozmiarze:https://github.com/elastic/elasticsearch-net-example/blob/master/src/NuSearch.Domain/Extensions/PartitionExtension.cs
źródło
Rozwijając odpowiedź Jan_V, właśnie uderzyłem w związany z nią przypadek w świecie rzeczywistym:
Musiałem użyć wersji FindFirstFile / FindNextFile w wersji Kernel32. Otrzymujesz uchwyt od pierwszego połączenia i podajesz go do wszystkich kolejnych połączeń. Zapakuj to w moduł wyliczający, a otrzymasz coś, czego możesz bezpośrednio użyć z foreach.
źródło