Po co używać.AsEnumerable() zamiast rzucać do IEnumerable?
Jedną z metod rozszerzenia na IEnumerable<T>
jest .AsEnumerable()
. Metoda ta przekształca obiekt wyliczeniowy, na który został wywołany, w instancję IEnumerable<T>
. Jednakże, ponieważ obiekt musi zaimplementować IEnumerable<T>
w celu zastosowania do tej metody rozszerzenia, konwersja do IEnumerable<T>
jest prostą kwestią odlewania do IEnumerable<T>
. Moje pytanie brzmi, dlaczego ta metoda w ogóle istnieje?
Przykład:
List<string> strings = new List<string>() { "test", "test2", "test3" };
IEnumerable<string> stringsEnum1 = strings.AsEnumerable();
IEnumerable<string> stringsEnum2 = (IEnumerable<string>)strings;
W powyższym przykładzie stringsEnum1
i stringsEnum2
są równoważne. Jaki jest sens rozszerzenia metoda?
Edit : jako następstwo, dlaczego istnieje metoda .AsQueryable()
, gdy rzut do IQueryable<T>
jest równoważny?
7 answers
Czytelność jest tutaj głównym problemem. Rozważmy to
Table.AsEnumerable().Where(somePredicate)
Jest znacznie bardziej czytelny niż
((IEnumerable<TableObject>)Table).Where(somePredicate).
W tym celu należy wykonać następujące czynności:]}
Table.Where(somePredicate)
.Select(someProjection)
.AsEnumerable()
.SomethingElse()
Kontra
((IEnumerable<SomeProjectionType>)Table.Where(somePredicate)
.Select(someProjection))
.SomethingElse()
Teraz, dlaczego taka metoda jest przydatna w ogóle pomyśl o przykładzie {[6] } w LINQ do SQL DataContext
. Ponieważ Table
jest IQueryable
implementuje IEnumerable
. Po wywołaniu metody Where
na takiej Table
i wyliczeniu przez wyniki, kod jest wykonanie, które ostatecznie powoduje wykonanie polecenia SQL na serwerze SQL. To, co robi AsEnumerable
, mówi: Nie, Nie chcę używać dostawcy LINQ do SQL do wykonywania Where
, chcę użyć implementacji LINQ do obiektów Where
.
W ten sposób wyliczamy nad
Table.Where(somePredicate)
W tym celu należy wykonać następujące czynności:]}
Table.AsEnumerable().Where(somePredicate)
Przenosi tabelę reprezentowaną przez Table
do pamięci i wykonuje Where
funkcjonalność w pamięci (a nie na SQL Server!)
Jest to punkt AsEnumerable
: aby umożliwić ukrycie określonej implementacji metod IEnumerable
i zamiast tego użyć standardowej implementacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 15:46:43
Wymyśliłem powód oprócz czytelności, choć związany z implementacją zapytań: używanie Linq do obiektów na anonimowych typach zwracanych przez innego dostawcę Linq. Nie możesz obsadzić anonimowego typu (lub zbioru anonimowych typów), ale możesz użyć .AsEnumerable()
, Aby wykonać obsadę za Ciebie.
Przykład:
// Get an IQueryable of anonymous types.
var query = from p in db.PeopleTable /* Assume Linq to SQL */
select new { Name = p.Name, Age = p.Age };
// Execute the query and pull the results into an IEnumerable of anonymous types
var enum = query.AsEnumerable();
// Use Linq to Objects methods to further refine.
var refined = from p in enum
select new
{
Name = GetPrettyName(p.Name),
DOB = CalculateDOB(p.Age, DateTime.Now)
};
Najwyraźniej powodem jest to, że chcemy użyć czegoś takiego jak Linq do SQL, aby ściągnąć niektóre rekordy do anonimowego typu, a następnie wykonać niestandardową logikę (która nie byłoby możliwe poprzez Linq do SQL) używając Linq do obiektów po stronie klienta.
Casting do IEnumerable<_anon>
nie jest możliwy, więc .AsEnumerable()
to jedyna droga.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 15:46:09
Jak czytam książkę C# 6.0 in a Nutshell
. Poniżej znajduje się przykład AsEnumerable
w książce.
Celem jest dodanie sekwencji IQueryable<T>
do IEnumerable<T>
, zmuszając kolejne operatory zapytań do wiązania się z operatorami Wyliczeniowymi zamiast z operatorami zapytań. Powoduje to, że reszta zapytania wykonuje lokalnie .
Aby zilustrować, Załóżmy, że mieliśmy MedicalArticles
tabelę w SQL Server i chcieliśmy użyć LINQ do SQL lub EF, aby pobrać wszystkie artykuły na temat grypy, których streszczenie zawierało mniej niż 100 słów. Dla tego ostatniego predykatu potrzebujemy wyrażenia regularnego:
Regex wordCounter = new Regex (@"\b(\w|[-'])+\b");
var query = dataContext.MedicalArticles
.Where (article => article.Topic == "influenza" &&
wordCounter.Matches (article.Abstract).Count < 100);
Problem polega na tym, że SQL Server nie obsługuje wyrażeń regularnych, więc dostawcy LINQ-to-db rzucą wyjątek, narzekając, że zapytanie nie może być przetłumaczone na SQL. Możemy to rozwiązać poprzez odpytywanie w dwóch krokach: najpierw pobierając wszystkie artykuły na temat grypy za pomocą zapytania LINQ do SQL, a następnie filtrując lokalnie dla abstraktów mniej niż 100 słów:
Regex wordCounter = new Regex (@"\b(\w|[-'])+\b");
IEnumerable<MedicalArticle> sqlQuery = dataContext.MedicalArticles
.Where (article => article.Topic == "influenza");
IEnumerable<MedicalArticle> localQuery = sqlQuery
.Where (article => wordCounter.Matches (article.Abstract).Count < 100);
Zliczalnie, możemy zrobić to samo w jednym zapytaniu:
var query = dataContext.MedicalArticles
.Where (article => article.Topic == "influenza")
.AsEnumerable()
.Where (article => wordCounter.Matches (article.Abstract).Count < 100);
Alternatywą dla wywołania liczby jest wywołanie Doarray lub ToList. zaletą AsEnumerable jest to, że nie wymusza natychmiastowego wykonywania zapytań , ani nie tworzy żadnej struktury pamięci masowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-06 09:33:03
To po prostu najmilszy i najkrótszy sposób na rzucanie do liczby mnogiej. Jeśli spojrzysz na to w reflektorze, zobaczysz, że nie robi nic poza zwróceniem obiektu jako liczby mnogiej.
Z MSDN:
AsEnumerable(Of TSource) (IEnumerable(Of TSource)) metoda nie ma innego wpływu niż na zmiana typu źródła w czasie kompilacji od typu, który realizuje IEnumerable (of T) to IEnumerable (of T) siebie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 15:38:43
Typy anonimowe są głównym powodem dostarczania tego rodzaju metod rozszerzeń. (nie można używać anonimowych typów w parametrach generycznych) Ale wywołanie metody może używać wnioskowania typu, pozwalając na pominięcie określania typu w parametrach ogólnych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-13 20:46:31
Jeśli na obiekcie znajduje się Metoda o tej samej nazwie co metoda rozszerzenia Linq, ukrywa ona metodę rozszerzenia. Korzystanie Zliczalne pozwala uzyskać na rozszerzenie.
To wydaje się być nowe w SP1.
Wczoraj miałem wiersz kodu, który wyodrębnił identyfikatory członków z tabeli danych:-
var lMmIds = new List<int>(
lDmMember.DataTable.Select(R => R.MmId)
);
Który działał dobrze, dopóki nie zainstalowałem SP1. Teraz nie będzie działać, jeśli nie będzie czytać
var lMmIds = new List<int>(
lDmMember.DataTable.AsEnumerable().Select(R => (int)((dsMtables.tbMMemberRow)R).MmId)
);
Edit: znalazłem prawdziwy powód
Jest tak, że można używać zarówno metod zdalnych (np. WHERE w instrukcji SQL), jak i metod lokalnych w tej samej instrukcji linq. Bez użycia liczby (np. tylko odlewania) spowoduje, że generator zapytań spróbuje utworzyć drzewo wyrażeń do zdalnego wykonania, które zawiera lokalną metodę. Umieszczenie liczby w zapytaniu spowoduje, że reszta tego zapytania zostanie wykonana lokalnie na wynikach zapytania zdalnego.
Od https://msdn.microsoft.com/en-us/library/bb335435 (v=vs.110). aspx
Typ tabeli reprezentujący tabelę bazy danych może mieć metodę Where, która przyjmuje argument predykatu jako drzewo wyrażeń i konwertuje drzewo do SQL w celu zdalnego wykonania. Jeśli zdalne wykonanie nie jest pożądane, na przykład dlatego, że predykat wywołuje metodę lokalną, można użyć metody numerycznej do ukrycia niestandardowych metod i zamiast tego utworzyć standardowe operatory zapytań dostępny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 11:19:01
Jak mówisz, jeśli typ implementuje już IEnumerable<T>
, to nie ma żadnej funkcjonalnej różnicy między uruchamianiem interfejsu a wywołaniem metody AsEnumerable
.
Moim zdaniem, i to tylko przypuszczenie, jest to, że wywołanie AsEnumerable
poprawia czytelność i zachowuje płynną sygnaturę innych metod rozszerzenia LINQ:
var query = ((IEnumerable<YourType>)yourCollection).Select(x => x.YourProperty);
// vs
var query = yourCollection.AsEnumerable().Select(x => x.YourProperty);
Pozwala również na typy, które nie implementują IEnumerable<T>
- na przykład, DataTable
- mieć własną wersję rozszerzenia AsEnumerable
. Pozwala to na kontynuuj używanie tego samego wzorca w zapytaniach przeciwko tym typom - nawet jeśli jest to inna metoda AsEnumerable
, którą wywołujesz - bez martwienia się o to, czy typ rzeczywiście implementuje IEnumerable<T>
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 15:48:30