Mam wątpliwości co do działania Enumeratorów i LINQ. Rozważ te dwa proste wybory:
List<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct().ToList();
lub
IEnumerable<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct();
Zmieniłem nazwy moich oryginalnych obiektów, aby wyglądało to na bardziej ogólny przykład. Samo zapytanie nie jest tak ważne. Chcę zapytać o to:
foreach (Animal animal in sel) { /*do stuff*/ }
Zauważyłem, że jeśli używam
IEnumerable
, kiedy debuguję i sprawdzam „sel”, którym w tym przypadku jest IEnumerable, ma on kilka interesujących elementów: „wewnętrzny”, „zewnętrzny”, „innerKeySelector” i „outerKeySelector”, pojawiają się te 2 ostatnie być delegatami. Członek „wewnętrzny” nie ma w nim instancji „Zwierzęcych”, lecz instancje „Gatunków”, co było dla mnie bardzo dziwne. Element „zewnętrzny” zawiera instancje „Zwierząt”. Zakładam, że dwaj delegaci określają, kto wchodzi i co wychodzi?Zauważyłem, że jeśli użyję „Wyraźny”, „wewnętrzny” zawiera 6 elementów (jest to niepoprawne, ponieważ tylko 2 są Wyróżniające), ale „zewnętrzny” zawiera prawidłowe wartości. Znów, prawdopodobnie delegowane metody to określają, ale jest to nieco więcej niż wiem o IEnumerable.
Co najważniejsze, która z dwóch opcji jest najlepsza pod względem wydajności?
Konwersja listy złych przez .ToList()
?
A może bezpośrednio za pomocą modułu wyliczającego?
Jeśli możesz, proszę wytłumacz trochę lub wrzuć linki, które wyjaśniają użycie IEnumerable.
źródło
IEnumerable<T>
będzie LINQ-To-Objects po pierwszej części, co oznacza, że wszystkie wykryte będą musiały zostać zwrócone, aby uruchomić Feline. Z drugiej stronyIQuertable<T>
pozwoli dopracować zapytanie, ściągając w dół tylko Feliny.Jest bardzo dobry artykuł napisany przez: TechBlog Claudio Bernasconiego tutaj: Kiedy używać IEnumerable, ICollection, IList i List
Oto kilka podstawowych informacji na temat scenariuszy i funkcji:
źródło
List
Jest to realizacjaIList
i jako taki posiada dodatkową funkcjonalność na górze w tychIList
(npSort
,Find
,InsertRange
). Jeśli zmusić się do wykorzystaniaIList
w ciąguList
, tracisz te metody, które mogą wymagaćIReadOnlyCollection<T>
[]
.Klasa, która implementuje
IEnumerable
pozwala na użycieforeach
składni.Zasadniczo ma metodę uzyskania następnego elementu w kolekcji. Nie potrzebuje całej kolekcji do zapamiętania i nie wie, ile jest w niej przedmiotów,
foreach
po prostu dostaje następny element, aż skończy się.Może to być bardzo przydatne w pewnych okolicznościach, na przykład w ogromnej tabeli bazy danych, w której nie chcesz kopiować całej rzeczy do pamięci przed rozpoczęciem przetwarzania wierszy.
Teraz
List
implementujeIEnumerable
, ale reprezentuje całą kolekcję w pamięci. Jeśli maszIEnumerable
i dzwonisz.ToList()
, tworzysz nową listę z zawartością wyliczenia w pamięci.Wyrażenie linq zwraca wyliczenie, a domyślnie wyrażenie jest wykonywane podczas iteracji za pomocą
foreach
. AnIEnumerable
LINQ Wykonuje oświadczenie gdy iteracyjneforeach
, ale można zmusić go do iteracji prędzej użyciu.ToList()
.Oto co mam na myśli:
źródło
foreach
podczas gdy List będzie przechodzić przez powiedz indeks. Teraz, jeśli chciałbym poznać count / długość zthing
wyprzedzeniem, IEnumerable nie pomoże, prawda?List
iArray
implementacjaIEnumerable
. Możesz myśleć oIEnumerable
najniższym wspólnym mianowniku, który działa zarówno w kolekcjach pamięci, jak i dużych, które otrzymują po jednym elemencie na raz. Kiedy dzwonisz,IEnumerable.Count()
możesz dzwonić do szybkiej.Length
nieruchomości lub przeglądać całą kolekcję - chodzi o to, że zIEnumerable
tobą nie wiesz. To może być problem, ale jeśli tylko będzieforeach
to wtedy nie obchodzi - kod będzie pracować zArray
lubDataReader
takie same.Nikt nie wspomniał o jednej istotnej różnicy, na ironię odpowiedział na pytanie zamknięte jako powielenie tego.
Zobacz Praktyczna różnica między List a IEnumerable
źródło
Najważniejszą rzeczą do zrozumienia jest to, że przy użyciu Linq zapytanie nie jest natychmiast oceniane. Jest prowadzony wyłącznie jako część iteracja uzyskany
IEnumerable<T>
w sposóbforeach
- to wszystko dziwne delegaci robią.Tak więc pierwszy przykład ocenia zapytanie natychmiast, wywołując
ToList
i umieszczając wyniki zapytania na liście.Drugi przykład zwraca an
IEnumerable<T>
zawierający wszystkie informacje potrzebne do późniejszego uruchomienia zapytania.Pod względem wydajności odpowiedź jest zależna . Jeśli potrzebujesz, aby wyniki zostały ocenione od razu (powiedzmy, że mutujesz struktury, o które pytasz później, lub jeśli nie chcesz, aby iteracja
IEnumerable<T>
trwała dłużej), użyj listy. W przeciwnym razie użyjIEnumerable<T>
. Domyślnie należy użyć oceny na żądanie w drugim przykładzie, ponieważ generalnie zużywa ona mniej pamięci, chyba że istnieje konkretny powód do przechowywania wyników na liście.źródło
Join
tym polega praca - wewnętrzna i zewnętrzna to dwie strony złączenia. Zasadniczo nie martw się o to, co jest w rzeczywistościIEnumerables
, ponieważ będzie to zupełnie inne niż twój kod. Martw się tylko o rzeczywistą moc wyjściową podczas iteracji :)Zaletą IEnumerable jest odroczenie wykonania (zwykle z bazami danych). Zapytanie nie zostanie wykonane, dopóki dane nie zostaną zapętlone. To zapytanie czeka, aż będzie potrzebne (inaczej leniwe ładowanie).
Jeśli wywołasz ToList, zapytanie zostanie wykonane lub „zmaterializowane”, jak lubię mówić.
Oba mają swoje zalety i wady. Jeśli wywołasz ToList, możesz usunąć tajemnicę, kiedy zapytanie zostanie wykonane. Jeśli pozostaniesz przy IEnumerable, zyskasz tę zaletę, że program nie wykona żadnej pracy, dopóki nie będzie faktycznie wymagany.
źródło
Podzielę się jedną nadużywaną koncepcją, do której wpadłem jednego dnia:
Spodziewany wynik
Aktualny rezultat
Wyjaśnienie
Podobnie jak w przypadku innych odpowiedzi, ocena wyniku została odroczona do momentu
ToList
na przykład wywołania lub podobnych metod wywołaniaToArray
.W tym przypadku mogę przepisać kod jako:
Graj wokół
https://repl.it/E8Ki/0
źródło
IEnumerable
to działa, ale teraz nie jest bardziej ponieważ wiem jak;)Jeśli wszystko, co chcesz zrobić, to wymienić je, użyj
IEnumerable
.Uważaj jednak, że zmiana wyliczanego zbioru oryginalnego jest niebezpieczną operacją - w tym przypadku będziesz chciał
ToList
najpierw. Spowoduje to utworzenie nowego elementu listy dla każdego elementu w pamięci, wyliczającIEnumerable
i dlatego jest mniej wydajny, jeśli wyliczysz tylko raz - ale bezpieczniejsze, a czasemList
metody są przydatne (na przykład w przypadkowym dostępie).źródło
IEnumerable
, to najpierw utworzenie listy (i iteracja nad nią) oznacza, że powtórzysz dwa elementy . Jeśli więc nie chcesz wykonywać operacji, które są bardziej wydajne na liście, oznacza to naprawdę niższą wydajność..ToList()
pomaga tutaj;)Oprócz wszystkich odpowiedzi zamieszczonych powyżej, oto moje dwa centy. Istnieje wiele innych typów niż List, które implementują IEnumerable, takie jak ICollection, ArrayList itp. Więc jeśli mamy IEnumerable jako parametr dowolnej metody, możemy przekazać dowolne typy kolekcji do funkcji. Tj. Możemy mieć metodę działania na abstrakcji, a nie na konkretnej implementacji.
źródło
Istnieje wiele przypadków (takich jak lista nieskończona lub bardzo duża), w których IEnumerable nie może zostać przekształcony w Listę. Najbardziej oczywistymi przykładami są wszystkie liczby pierwsze, wszyscy użytkownicy Facebooka z ich szczegółami lub wszystkie przedmioty w serwisie eBay.
Różnica polega na tym, że obiekty „Lista” są przechowywane „tu i teraz”, podczas gdy „IEnumerable” obiekty działają „tylko jeden na raz”. Więc jeśli przeglądam wszystkie elementy w serwisie eBay, jeden na raz byłby czymś, co poradziłby sobie nawet mały komputer, ale „.ToList ()” z pewnością zabrakłoby mi pamięci, bez względu na to, jak duży był mój komputer. Żaden komputer nie może sam w sobie zawierać i przetwarzać tak dużej ilości danych.
[Edytuj] - Nie trzeba dodawać - to nie jest „ani to, ani tamto”. często miałoby sens zastosowanie zarówno listy, jak i IEnumerable w tej samej klasie. Żaden komputer na świecie nie może wyświetlić wszystkich liczb pierwszych, ponieważ z definicji wymagałoby to nieskończonej ilości pamięci. Ale możesz łatwo pomyśleć o tym,
class PrimeContainer
który zawieraIEnumerable<long> primes
, który z oczywistych powodów również zawieraSortedList<long> _primes
. wszystkie liczby pierwsze obliczone do tej pory. następna liczba pierwsza, która zostanie sprawdzona, zostanie uruchomiona tylko na podstawie istniejących liczb pierwszych (do pierwiastka kwadratowego). W ten sposób zyskujesz zarówno liczby pierwsze pojedynczo (IEnumerable), jak i dobrą listę „liczb pierwszych do tej pory”, co jest całkiem dobrym przybliżeniem całej (nieskończonej) listy.źródło