The LINQ Project
NET Language Integrated Query
September 2005
Don Box, Architect, Microsoft Corporation and
Anders Hejlsberg, Distinguished Engineer, Microsoft Corporation
Перевод на русский и дополнение – Даниил Абрамов aka Exception
Что такое LINQ, и для чего он нужен
Аббревиатура LINQ расшифровывается как “Language INtegrated Query”. Это сочетание буквально переводится «Запросы, интегрированные в язык». Что же эта технология из себя представляет, и для чего она нужна? В этой статье я постараюсь ответить на этот и на многие другие вопросы. По пути повествования я также расскажу, что ещё, кроме LINQ, нас ждёт в Visual Basic 9.0 и C# 3.0.
На данном этапе развития объектно-ориентированных технологий наиболее сложным и проблематичным является доступ к информации, которая изначально не определена объектами. Двумя наиболее распространёнными источниками подобной информации являются базы данных и XML. Оговорюсь: существуют объектные базы данных, но их рассмотрение и интеграция с.NET выходит за рамки данного обзора.
Что же позволяет нам LINQ? LINQ, как это видно из названия, является технологией, которая позволяет использовать язык запросов, похожий с SQL, прямо в коде программы. LINQ будет поддерживаться компиляторами Visual Basic 9.0 и C# 3.0 (а точнее, уже поддерживается VB.NET 2005 и C# 2.0 при установке дополнительных компонент, которые мы обсудим отдельно); относительно его, так сказать, встроенной поддержки другими языками.NET (J# и C++/CLI) пока что достоверных сведений нет. Впрочем, в любом случае, поддерживаться он всё равно будет, как ни крути, но гораздо более кривым способом. Давайте же рассмотрим LINQ более детально.
LINQ определяет набор стандартных операторов запросов (standard query operators), которые могут использоваться для фильтрации, выборки и сортировки элементов, определённых типом IEnumerable<T> (перечислений).
|
Примечание
Под перечислением здесь и далее понимается объект, реализующий IEnumerable<T>, а не перечисление в привычном понимании смысла этого слова (enumeration).
Таким образом, мы можем фильтровать содержимое любых коллекций, массивов, да и вообще любых перечислимых объектов с помощью такого синтаксиса:
Код C# 3.0
string[] forums = {"Vingrad", "RSDN", "GotDotNet"};
IEnumerable<string> coolForum = from forum in forums
where forum.Length == 7
select forum.ToUpper();
Код VB.NET 9.0
Dim forums() As String = {"RSDN", "Vingrad", "GotDotNet"}
Dim coolForum As IEnumerable(Of String) = Select forum.ToUpper() _
From forum In forums _
Where forum.Length = 7
Как можно заметить, у C# и VB несколько отличается порядок ключевых слов: в Visual Basic 9.0 используется более традиционный вариант (Select … From … Where … Order By …), позаимствованный из SQL, в то время, как в C# используется новый вариант (from … where … orderby … select …). Дискуссию по поводу этого вопроса можно почитать здесь. Впрочем, это только дело вкуса.
Итак, давайте вернёмся к LINQ. Как я уже сказал, LINQ определяет стандартные операторы запросов, такие, как Select, Where, и т.п. Однако, на этом дело не заканчивается. Вы также можете определять собственные операторы запросов (query operators) и переопределять существующие. Какой смысл в переопределении? Наприер, Dlinq (технология LINQ для доступа к БД) транслирует команды запросов языка в аналогичные запросы T-SQL. Более подробно о переопределении написано ниже. Впрочем, перед тем, как кликать по ссылке, советую всё-таки почитать начало:))
Благодаря расширяемости LINQ появились две его реализации для эффективного и удобного взаимодействия с реляционными данными (DLinq) и с XML (XLinq). Их рассмотрение мы оставим на чуть более позднее время, скажу только, что мне они кажутся куда более полезными, чем сам по себе LINQ. Короче говоря, дорогие читатели, придержите своё любопытство и прочитайте эту часть статьи, где рассказывается о LINQ в общем и целом:)
|
Стандартные операторы запросов
Поскольку всё проще понять на примере, вот довольно простой пример использования LINQ. Попробуйте сами угадать, что он выводит:
Код C# 3.0
using System;
using System.Query;
using System.Collections.Generic;
class Program {
static void Main() {
string[] forums = {"Vingrad", "RSDN", "GotDotNet"};
IEnumerable<string> coolForum = from forum in forums
where forum.Length == 7
orderby forum
select forum.ToUpper();
foreach (string forum in coolForum)
Console.WriteLine(forum);
Console.ReadLine();
}
}
Код VB.NET 9.0
Imports System
Imports System.Query
Imports System.Collections.Generic
Module Program
Sub Main()
Dim forums() As String = {"Vingrad", "RSDN", "GotDotNet"}
Dim coolForum As IEnumerable(Of String) = _
Select forum.ToUpper() _
From forum In forums _
Where forum.Length = 7 _
Order By forum
For Each forum As String In coolForum
Console.WriteLine(forum)
Next
Console.ReadLine()
End Sub
End Module
Соответственно, результатом выполнения данной программы будет следующее:
VINGRAD
Чтобы понять, как работает LINQ, давайте ещё раз рассмотрим оператор запроса нашей программы:
Код C# 3.0
IEnumerable<string> coolForum = from forum in forums
where forum.Length == 7
orderby forum
select forum.ToUpper();
Код VB.NET 9.0
Dim coolForum As IEnumerable(Of String) = _
Select forum.ToUpper() _
From forum In forums _
Where forum.Length = 7 _
Order By forum
Здесь переменная coolForum инициализируется выражением запроса (query expression). Скажу по секрету, на самом деле она инициализируется типом System.Query.OrderedSequence<string, string>, но пока что нам это довольно мало говорит:) В данном примере используются стандартные операторы запросов, в частности where, orderby и select.
|
И C#, и Visual Basic поддерживают так называемый синтаксис запросов (query syntax). Подобно операторам using и foreach, которые на самом деле являются сокращённым вариантом довольно громоздкой записи, синтаксис запросов также является лишь упрощённым вариантом вот такой записи:
Код C# 3.0
IEnumerable<string> coolForum = forums
.Where(f => f.Length == 7)
.OrderBy(f => f)
.Select(f => f.ToUpper());
Примечание
Некоторых почему-то пугает такой тип записи, когда каждая точка находится на разной строке. Поясню: этот код можно записать и как
Код C# 3.0
forums.Where(f => f.Length == 7).OrderBy(f => f).Select(f => f.ToUpper());
Просто такой вариант менее читаем.
Аргументы, переданные методам (мы их будем называть операторами запросов, или просто операторами) Where, OrderBy и Select, называются λ-выражениями (lambda expressions, произносится «лямбда-выражения»), которые являются некоторого рода эволюцией анонимных делегатов, позволяя их записать в ещё более сокращённой форме. О них мы ещё поговорим чуть ниже. Именно компактность λ-выражений позволяет использовать их в тексте запроса без существенного увеличения объёма кода.