Зачем использовать.AsEnumerable () вместо приведения к IEnumerable?
один из методов расширения на IEnumerable<T> и .AsEnumerable(). Этот метод преобразует перечисляемый объект, на который он был вызван, в экземпляр IEnumerable<T>. Однако, поскольку объект должен реализовать IEnumerable<T> чтобы применить к этому методу расширения, преобразование в IEnumerable<T> Это простой вопрос приведения к IEnumerable<T>. Мой вопрос в том, почему этот метод Вообще существует?
пример:
List<string> strings = new List<string>() { "test", "test2", "test3" };
IEnumerable<string> stringsEnum1 = strings.AsEnumerable();
IEnumerable<string> stringsEnum2 = (IEnumerable<string>)strings;
в приведенном выше примере,stringsEnum1 и stringsEnum2 эквивалентны. Что точка метода расширения?
Edit: как следствие, почему .AsQueryable() метод при приведении к IQueryable<T> эквивалентно?
7 ответов:
читаемость является главной проблемой здесь. Считайте, что
Table.AsEnumerable().Where(somePredicate)гораздо более читабельно, чем
((IEnumerable<TableObject>)Table).Where(somePredicate).или представьте, что вы хотите выполнить часть запроса на SQL Server, а остальное в памяти:
Table.Where(somePredicate) .Select(someProjection) .AsEnumerable() .SomethingElse()и
((IEnumerable<SomeProjectionType>)Table.Where(somePredicate) .Select(someProjection)) .SomethingElse()теперь, что касается того, почему такой метод полезен вообще подумайте о примере a
Tableв LINQ to SQLDataContext. КакTableэтоIQueryableосуществляетIEnumerable. Когда вы вызываетеWhereметод такаяTableи перечислить через результаты, выполняется код, который в конечном итоге приводит к выполнению инструкции SQL на SQL Server. ЧтоAsEnumerabledoes is говорит, Нет, я не хочу использовать поставщик LINQ to SQL для выполненияWhere, Я хочу использовать реализацию LINQ to ObjectsWhere.таким образом перечисляя над
Table.Where(somePredicate)вызывает выполнение запроса на сервере SQL при перечислении через
Table.AsEnumerable().Where(somePredicate)приносит в таблице представлен
Tableв память и выполняетWhereфункциональность в памяти (а не на SQL Server!)это точка
AsEnumerable: чтобы вы могли скрыть конкретную реализациюIEnumerableметоды и вместо этого использовать стандартную реализацию.
Я думал о причине помимо читаемости, хотя и связанной с реализацией запроса: использование Linq для объектов анонимных типов, возвращаемых через другого поставщика Linq. Вы не можете привести к анонимному типу (или коллекции анонимных типов), но вы можете использовать
.AsEnumerable()для выполнения приведения для вас.пример:
// 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) };ясно, что причина здесь в том, что мы хотим использовать что-то вроде Linq to SQL, чтобы вытащить некоторые записи в анонимный тип, а затем выполнить некоторые пользовательская логика (это было бы невозможно с помощью Linq to SQL), используя Linq to Objects на стороне клиента.
кастинг
IEnumerable<_anon>невозможно, так что.AsEnumerable()- это единственный путь.спасибо всем, кто ответил, чтобы помочь мне собрать это вместе. =)
как я читаю книгу
C# 6.0 in a Nutshell. Ниже приведен примерAsEnumerableв книге.
цель состоит в том, чтобы бросить
IQueryable<T>последовательностьIEnumerable<T>, заставляя последующие операторы запроса привязываться к перечисляемым операторам вместо запрашиваемых операторов. Это приводит к выполнению оставшейся части запроса локально.для иллюстрации предположим, что у нас есть
MedicalArticlesтаблица в SQL Server и хотел использовать LINQ to SQL или EF для получения всех статей на грипп, резюме которого содержало менее 100 слов. Для последнего предиката, нам нужно регулярное выражение:Regex wordCounter = new Regex (@"\b(\w|[-'])+\b"); var query = dataContext.MedicalArticles .Where (article => article.Topic == "influenza" && wordCounter.Matches (article.Abstract).Count < 100);проблема в том, что SQL Server не поддерживает регулярные выражения, поэтому поставщики LINQ-to-db будут выдавать исключение, жалуясь, что запрос не может быть переведен на SQL. Мы можем решить эту проблему путем запроса в два этапа: сначала извлекая все статьи по гриппу через запрос LINQ to SQL, а затем фильтруя локально для тезисов менее 100 слова:
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);С AsEnumerable, мы можем сделать то же самое в одном запросе:
var query = dataContext.MedicalArticles .Where (article => article.Topic == "influenza") .AsEnumerable() .Where (article => wordCounter.Matches (article.Abstract).Count < 100);альтернативой вызову AsEnumerable является вызов ToArray или ToList. преимущество AsEnumerable заключается в том, что он не вызывает немедленного выполнения запроса, и он не создает никакой структуры хранения.
Это просто самый приятный и короткий способ бросить в IEnumerable. Если вы посмотрите на него в отражателе, вы можете увидеть, что он ничего не делает, кроме возврата объекта как IEnumerable.
от MSDN:
AsEnumerable(Of TSource)(IEnumerable (Of TSource)) метод не имеет никакого эффекта помимо изменение типа источника во время компиляции от типа, который реализует Интерфейс IEnumerable(т) к IEnumerable(Т) себя.
анонимные типы являются основной причиной для предоставления таких методов расширения. (вы не можете использовать анонимные типы в универсальных параметрах) Но вызов метода может использовать вывод типа, позволяющий опустить указание типа в общих параметрах.
Если есть метод для объекта, который имеет то же имя, что и метод расширения Linq, он скрывает метод расширения. Использование AsEnumerable позволяет получить расширение.
это кажется новым в SP1.
вчера у меня была строка кода, которая добывается идентификаторов из таблицы данных:-
var lMmIds = new List<int>( lDmMember.DataTable.Select(R => R.MmId) );который работал просто отлично, пока я не установил SP1. Теперь он не будет работать, если он не читает
var lMmIds = new List<int>( lDmMember.DataTable.AsEnumerable().Select(R => (int)((dsMtables.tbMMemberRow)R).MmId) );Edit: я нашел настоящий причина
это так, что вы можете использовать как удаленные методы (например, где в инструкции SQL), так и локальные методы в том же операторе linq. Без использования AsEnumerable (т. е. просто приведение) он сделает попытку генератора запросов создать дерево выражений для удаленного выполнения, содержащее локальный метод. Добавление AsEnumerable в запрос приведет к тому, что остальная часть этого запроса будет выполняться локально по результатам удаленного запроса.
от https://msdn.microsoft.com/en-us/library/bb335435 (v=vs. 110). aspx
тип таблицы, представляющий таблицу базы данных, может иметь метод Where, который принимает аргумент предиката в качестве дерева выражений и преобразует дерево в SQL для удаленного выполнения. Если удаленное выполнение не требуется, например, потому что предикат вызывает локальный метод, метод AsEnumerable можно использовать для скрытия пользовательских методов и вместо этого сделать стандартные операторы запроса доступный.
как вы говорите, если тип уже реализует
IEnumerable<T>тогда на самом деле нет никакой функциональной разницы между приведением к интерфейсу или вызовомAsEnumerableметод.моя догадка, и это только догадка, это вызов
AsEnumerableулучшает читаемость и сохраняет плавную подпись других методов расширения LINQ:var query = ((IEnumerable<YourType>)yourCollection).Select(x => x.YourProperty); // vs var query = yourCollection.AsEnumerable().Select(x => x.YourProperty);она также позволяет типы, которые не реализуют
IEnumerable<T>-например,DataTable- иметь свою собственную версию
Comments