Класс Enumerable LINQ - Enumerable изнутри
ОГЛАВЛЕНИЕ
Enumerable изнутри
Класс Enumerable играет важную роль в каждом создаваемом запросе LINQ. Например, представьте, что в ваш проект входит класс Product и общие экземпляры List of Product (как в примере проекта). Вы создали на основе примера экземпляр класса SimpleDataContext, который наполняет данными список Products, и пишете запрос, подобный следующему.
Dim db As New SimpleDataContext()
Dim query = _
From prod In db.Products _
Where prod.CategoryID = 1 _
Order By prod.ProductName _
Select prod.ProductName
Если вы долго размышляли над этим, вероятно, вы осознали, что компилятор Visual Basic должен «за кадром» преобразовать синтаксис типа SQL в некоторый набор вызовов методов из некоторого экземпляра подобного типа. Действительно, в этом примере свойство Products класса SimpleDataContext имеет тип List(Of Product), и, как вы, возможно, догадались, тип List(Of T) реализует интерфейс IEnumerable(Of T). Компилятор преобразует ключевые слова LINQ в соответствующие вызовы методов расширения из класса типа Enumerable. А именно, можно создать в точности такой же набор команд, переписав запрос LINQ следующим образом.
Dim query = _
db.Products _
.Where(Function(prod) CBool(prod.CategoryID = 1)) _
.OrderBy(Function(prod) prod.ProductName) _
.Select(Function(prod) prod.ProductName)
Если изучить промежуточный язык (IL), созданный компилятором, с помощью запроса LINQ, использующего ключевые слова Visual Basic, будет видно, что компилятор преобразует ключевые слова Visual Basic в вызовы соответствующих методов класса Enumerable. В результате расширяется поведение класса System.Collections.Generic.List(Of T). (По существу, это легко определить — загляните в документацию по членам этого конкретного класса, и вы увидите список методов расширения, большая часть которых определяется классом Enumerable.)
Что все это означает для вас? Поскольку методы расширения класса Enumerable могут обрабатывать многие другие классы, включая Array и List, есть возможность использовать методы класса Enumerable не только для создания запросов LINQ, но также для манипулирования поведением массивов и других структур данных.
Если изучить документацию по методам расширения класса Enumerable, выяснится, что все члены являются общими (Shared). В итоге у вас есть два варианта вызова метода. Во-первых, его можно вызывать как метод декларативного типа, передавая экземпляр расширенного класса (в предположении, что переменная с результатами имеет тип, который может быть обработан методом Count), следующим образом.
Dim itemCount = _
Enumerable.Count(results, _
Function(prod) prod.CategoryID = 3)
Count можно вызвать также, как если бы он был методом экземпляра самой коллекции. При таком способе вызова метода расширения вам не требуется передавать первый параметр.
Dim itemCount = _
results.Count(Function(prod) _
prod.CategoryID = 3)
Visual Basic и C# по-разному выполняют преобразование ключевых слов в вызовы методов расширения. Visual Basic предоставляет большее, чем C#, число ключевых слов, которые можно использовать в запросах LINQ. Например, с помощью ключевого слова Take можно создать запрос LINQ в Visual Basic следующим образом.
Dim db As New SimpleDataContext()
Dim query = _
From prod In db.Products _
Where prod.CategoryID = 1 _
Order By prod.ProductName _
Take 10 _
Select prod.ProductName
Можно также использовать метод расширения Take, предоставляемый классом Enumerable, следующим образом.
Dim query = _
(From prod In db.Products _
Where prod.CategoryID = 1 _
Order By prod.ProductName _
Select prod.ProductName).Take(10)
Поскольку C# не предоставляет ключевого слова Take, не остается другого выбора, кроме как явно вызвать метод Take. На рис. 1 представлено соответствие ключевых слов запросов LINQ в Visual Basic и соответствующих методов класса Enumerable.
Рис. 1 Связь ключевых слов LINQ и методов класса Enumerable
Ключевое слово запроса LINQ в Visual Basic | Метод класса Enumerable |
---|---|
Aggregate … Into … All | All |
Aggregate … Into … All | Any |
Aggregate … Into … Average | Average |
Aggregate … Into … Count | Count |
Aggregate … Into … LongCount | LongCount |
Aggregate … Into … Max | Max |
Aggregate … Into … Min | Min |
Aggregate … Into … Sum | Sum |
Distinct | Distinct |
Group By | GroupBy |
Group Join | GroupJoin |
Order By | OrderBy |
Order By … Descending | OrderByDescending |
Order By (с несколькими полями) | ThenBy |
Order By … Descending (с несколькими полями) | ThenByDescending |
Select | Select |
Skip | Skip |
Take | Take |
Take While | TakeWhile |
Where | Where |