W mojej aplikacji sieci web ASP.net MVC4 używam IEnumerables, próbując podążać za mantrą, aby programować interfejs, a nie implementację.
Return IEnumerable(Of Student)
vs
Return New List(Of Student)
Ludzie każą mi używać List, a nie IEnumerable, ponieważ listy wymuszają wykonanie zapytania, a IEumerable nie.
Czy to naprawdę najlepsza praktyka? Czy jest jakaś alternatywa? Czuję się dziwnie, używając konkretnych obiektów, w których można zastosować interfejs. Czy moje dziwne uczucie jest uzasadnione?
.net
programming-practices
asp.net-mvc
entity-framework
Rowan Freeman
źródło
źródło
Odpowiedzi:
Są chwile, kiedy wykonywanie
ToList()
zapytań linq może być ważne, aby zapewnić wykonanie zapytań w czasie i w kolejności, w jakiej się spodziewają. Te scenariusze są jednak rzadkie i nie należy się tym zbytnio przejmować, dopóki nie trafią na nie.Krótko mówiąc, używaj
IEnumerable
zawsze, gdy potrzebujesz tylko iteracji, używaj,IList
gdy potrzebujesz bezpośrednio indeksować i potrzebujesz tablicy o dynamicznym rozmiarze (jeśli potrzebujesz indeksowania na tablicy o stałym rozmiarze, po prostu użyj tablicy standardowej).Jeśli chodzi o czas wykonania, zawsze możesz użyć listy jako
IEnumerable
zmiennej, więc możesz zwrócić wartośćIEnumerable
, wykonując a.ToList();
, lub przekazać parametr jakoIEnumerable
wykonanie.ToList()
wIEnumerable
celu wymuszenia wykonania natychmiast i tam. Uważaj tylko, aby za każdym razem, gdy wymusisz wykonanie z.ToList()
tobą, nie trzymaj sięIEnumerable
zmiennej, którą właśnie to zrobiłeś, i wykonaj ją ponownie, w przeciwnym razie skończy się to niepotrzebnym podwajaniem iteracji w zapytaniu LINQ.Jeśli chodzi o MVC, naprawdę nie ma tu nic specjalnego do odnotowania. Będzie przestrzegać tych samych reguł czasu wykonania co reszta .NET, myślę, że możesz mieć kogoś, kto był trochę zamieszany spowodowany opóźnioną semantyką wykonania w przeszłości i obwiniał to MVC, mówiąc, że jest to w jakiś sposób powiązane, ale to jest nie. Opóźniona semantyka wykonania na początku wprowadza wszystkich w błąd (a nawet później przez dłuższy czas; mogą być trudne). Znów jednak, nie przejmuj się nim, dopóki naprawdę nie zależy ci na tym, aby zapytanie LINQ nie zostało wykonane dwukrotnie lub nie wymagało wykonania go w określonej kolejności względem innego kodu, w którym to momencie przypisz zmienną do siebie. żeby wymusić egzekucję, a wszystko będzie dobrze.
źródło
List
omijanieList
sugeruje, że zawartość listy zostanie zmodyfikowana. Jeśli chcesz zwrócić kolekcję, użyjIReadOnlyCollection
.List
służy do stosowania w ramach metod i do wymiany między metodami modyfikującymi listę. To jest to!Istnieją dwa problemy.
Do momentu osiągnięcia pętli „Dane procesowe” zapytanie może przestać być prawidłowe. Na przykład, jeśli zapytanie jest uruchamiane w obiekcie DataContext, który został już usunięty, kod wygeneruje wyjątek. Tego rodzaju rzeczy stają się bardzo mylące, gdy przetwarzasz zapytanie w innym kontekście niż miejsce, w którym je utworzyłeś.
Drugi problem polega na tym, że połączenie nie zostanie zwolnione, dopóki pętla „Dane procesowe” się nie zakończy. Jest to problem tylko wtedy, gdy „Dane procesowe” są złożone. Zostało to wspomniane na stronie http://msdn.microsoft.com/en-us/library/bb386929.aspx :
Te problemy sprawiają, że zachęca się Cię do upewnienia się, że zapytanie zostało faktycznie wykonane, np. Przez telefon
ToList()
. Jednak, jak sugeruje Jimmy, nic nie stoi na przeszkodzie, aby zwrócić listę jako IEnumerable.Zasadniczo zalecam unikanie iteracji nad IEnumerable więcej niż jeden raz. Zakładając, że konsumenci twojego kodu przestrzegają tej reguły, nie uważam za obawy, że ktoś może trafić dwukrotnie w bazę danych, wykonując zapytanie dwukrotnie.
źródło
Kolejną zaletą wyliczenia
IEnumerable
wczesnego jest to, że wyjątki zostaną zgłoszone w odpowiednim miejscu. Pomaga to w debugowaniu.Na przykład, jeśli masz wyjątek zakleszczenia w jednym z widoków Razor, tak naprawdę nie byłoby tak jasne, jak gdyby wyjątek wystąpił podczas jednej z metod dostępu do danych.
źródło
IEnumerable
która może rzucić, prawdopodobnie popełni błąd. OdroczoneIEnumerable
metody powinny być podzielone na dwie: jedna nieodroczona metoda sprawdza parametry i konfiguruje, w razie potrzeby wyrzucając (powiedzmy, z powodu argumentu zerowego). Następnie zwraca wywołanie do prywatnej implementacji, które jest odroczone. Nie sądzę, że moje komentarze są całkowicie sprzeczne z twoją odpowiedzią, ale myślę, że pominąłeś ważny aspekt w swojej odpowiedzi, który jest semantycznym znaczeniem użyciaIEnumerable
vs. aList
(mutacja) vs.IReadOnlyCollection
(brak korzyści dla odroczenie) .