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?

Author: Erik Forbes, 2010-01-06

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.

 77
Author: jason,
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.

Dziękuję wszystkim, którzy pomogli mi to poskładać. =)
 14
Author: Erik Forbes,
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.

 4
Author: Timeless,
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.

 3
Author: Meta-Knight,
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.

 3
Author: james,
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.

 3
Author: Richard Petheram,
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>.

 2
Author: LukeH,
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