Зачем использовать.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> эквивалентно?

867   7  

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 SQL DataContext. Как Table это IQueryable осуществляет IEnumerable. Когда вы вызываете Where метод такая Table и перечислить через результаты, выполняется код, который в конечном итоге приводит к выполнению инструкции SQL на SQL Server. Что AsEnumerable does is говорит, Нет, я не хочу использовать поставщик LINQ to SQL для выполнения Where, Я хочу использовать реализацию LINQ to Objects Where.

таким образом перечисляя над

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

    Ничего не найдено.