Один из дополнительных методов на 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
эквивалентны. Какой смысл дополнительного метода?
Править: Как заключение, почему там .AsQueryable()
метод при кастинге к IQueryable<T>
эквивалентно?
] Читабельность здесь основная проблема. Считайте, что[
] [Table.AsEnumerable().Where(somePredicate)
]
[]намного более читабельная, чем[
] [((IEnumerable<TableObject>)Table).Where(somePredicate).
]
[]Или представьте себе желание выполнить часть запроса на SQL сервере, а остальную часть - в памяти:[
] [Table.Where(somePredicate)
.Select(someProjection)
.AsEnumerable()
.SomethingElse()
]
[]против[
] [((IEnumerable<SomeProjectionType>)Table.Where(somePredicate)
.Select(someProjection))
.SomethingElse()
]
[]Теперь, а зачем вообще полезен такой метод, вспомните пример []Table[
] в LINQ to SQL []DataContext[
]. Так как []Table[
] является []IQueryable[
], то он реализует []IEnumerable[
]. Когда вы вызываете метод [] Where[
] на такой []Table[
] и перечисляете по результатам, выполняется код, который в конечном итоге приводит к выполнению SQL-запроса на SQL-сервере. Что делает []AsEnumerable[
], это говорит, нет, я не хочу использовать LINQ to SQL провайдера для выполнения []Where[
], я хочу использовать LINQ to Objects реализацию []Where[
]. [
]Таким образом, перечисление по[
] [Table.Where(somePredicate)
]
[] вызывает запрос на SQL-сервере, а перечисление по[
] [Table.AsEnumerable().Where(somePredicate)
]
[] приносит в память таблицу, представленную []Table[
], и выполняет функцию []Where[
] в памяти (а не на SQL-сервере! )[
]В этом и заключается смысл []AsEnumerable[
]: позволить скрыть конкретную реализацию методов []IEnumerable[
] и вместо этого использовать стандартную реализацию.[
Я придумал причину, помимо удобочитаемости, хотя и связанную с реализацией запроса: использование Linq to Objects на анонимных типах, возвращаемых через другой 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()
- это единственный путь.
Спасибо всем, кто ответил, что помогли мне собрать это вместе. =)
.] Это просто милейший и кратчайший путь к IEnumerable. Если вы посмотрите на него в рефлекторе, то увидите, что он ничего не делает, кроме как возвращает объект как IEnumerable.[
] []Из MSDN:[
] [] []]The AsEnumerable(Of Источник)(IEnumerable(Of TSource)) метод не имеет никакого эффекта, кроме как изменить тип источника компилируемого времени от типа, который применяет IEnumerable(of T) to IEnumerable(of T) себя.[
] [
Как вы говорите, если тип уже реализует IEnumerable
, то функциональной разницы между приведением к интерфейсу и вызовом метода AsEnumerable
на самом деле нет.
Моя догадка, и это всего лишь догадка, заключается в том, что вызов AsEnumerable
улучшает читабельность и сохраняет беглость сигнатуры других методов расширения LINQ:
var query = ((IEnumerable<YourType>)yourCollection).Select(x => x.YourProperty);
// vs
var query = yourCollection.AsEnumerable().Select(x => x.YourProperty);
Он также позволяет типам, которые не реализуют IEnumerable
- например, - иметь свою версию расширения DataTable
- иметь свою версию AsEnumerable
. Это позволяет продолжить использование того же паттерна в запросах против этих типов - даже если это другой метод AsEnumerable
, - не беспокоясь о том, реализует ли данный тип на самом деле IEnumerable
.