LINQ は、"Language-Integrated Query"の略です。
クエリ "query" というと、まっさきに思い浮かぶことは SQL "Structured Query Language" ですね。これは、リレーショナル データベースに対するデータ操作を行うためのスクリプト系の言語です。
LINQ に対する日本語は「統合言語クエリ」ですが、「統合」は、SQL に限らず、データソースの種類ごとに異なる言語を使っていたものを統一した言語で操作可能にしようという意味を含んでいます。
.NET Framework における LINQ は、次の 4 つの分野に適用できます(最近、これらに加えて、いろいろな LINQ が提案されています)。
私はデータベースに対する知識やテストするための環境がありませんので、.NET Framework コレクションと XML ドキュメントの 2 つの分野における LINQ を取り上げます。
ちなみに、"LINQ to 〜" をキーワードにして .NET Framework SDK を検索すると、以下の 6 つにヒットしました。これらに加えて、性格は異なりますが、"Parallel LINQ" (PLINQ) もあります。
ところで、.NET Framework および C# の開発者である Anders Hejlsberg が LINQ について解説する文書の中で、オブジェクト指向プログラミングテクノロジ(.NET Framework 的なプログラミング手法)に対応しないものとしてリレーショナルデータベースと XML とを挙げていて、その解決策として開発言語やランタイムに固有の機能を盛り込むのではなく、LINQ という汎用性の高いアプローチを採用したということです。
LINQ の本質はその名前から想像できるように、「クエリ "query"」にあります。"query" の英語としての意味は、「問い合わせ」ですが、LINQ におけるそれは「要求」のほうがいいかもしれません。つまり、「こんなデータをよこせ」と要求することと理解するほうが分かりやすいと思います。
データを操作しようとするとき、従来の手法ではゴリゴリとコードを書くほかないのですが、LINQ を使えば単にデータを要求するだけです。つまり、Anders Hejlsberg は LINQ によるプログラムレス化(こんな言葉があるかどうかは知りませんが)を目指したのではないかと思います。IEnumerable<T> インターフェースを継承するデータ型に限られてはいますが。
.NET Framework SDK では、コレクションと配列とを含めて「シ−ケンス "sequence"」と呼んでいます。これらを総称して、「クエリ可能型」と呼ぶことがあります。
シーケンスとは、IEnumerable または IEnumerable <T> インターフェイスを継承するオブジェクトと考えていいと思います。これは、ほとんどのジェネリックコレクションと配列とを含みます。つまり、LINQ to Objects とは LINQ を .NET Framework のコレクションまたは配列に適用することです。
非ジェネリック IEnumerable インターフェイスを継承する ArrayList クラスなどもクエリ可能型です。
LINQ を XML ドキュメントに適用することです。
XML ドキュメントを操作するとき、DOM "Document Object Model" を利用する方法と LINQ to XML による方法とがあります。一般論で言えば、LINQ to XML のほうが簡単で、便利です。Microsoft もそう言っています。
"Parallel" は、並列コンピューティング "Parallel Computing" を意味します。並列コンピューティングとは、CPU が複数のコアを持つとか、複数の CPU を持つ場合に、一つの処理を並列的に処理する仕組みです。.NET Framework 4.0 は、並列コンピューティングをサポートしますので、利用することができます。
並列コンピューティングというと難しいのではないかと思うかもしれませんが、少なくとも、LINQ に関する限り、簡単に利用できます。つまり、並列コンピュータを利用可能なときはそうしろと指示するだけです。そうすべきかどうかは .NET Framework が自動的に判定します。
シーケンス "sequence" の英語としての意味は、「連続するもの」ですが、LINQ 用語としては、「コレクション」または「配列」と考えていいと思います。.NET Framework 的に言うと、IEnumerable、IEnumerable<T> または IQueryable<T> インターフェイスを実装する型ですね。
シングルトン "singleton" は、「一つのもの」という意味で、コレクション(配列を含む)でない型(単純型)です。
拡張メソッドとは、Smalltalk、PHP、Ruby、Python などの動的言語では一般的である "duck typing" の柔軟性と、静的に型指定する言語のパフォーマンスとコンパイル時検証を組み合わせたもので、指定の型に対して、その型がもともと持っていたメソッドであるかのように定義したメソッドです。
拡張メソッドは、static なクラス内の static なメソッドとして定義しなければなりません。以下のコードは、System.Linq.Enumerable クラスの Where メソッドの実装です。
using System; using System.Collections.Generic; namespace System.Linq { public static class Enumerable ← static なクラス { public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate) ← static なメソッド { foreach (T item in source) { if (predicate(item)) yield return item; ← 遅延実行のポイント(後述) } } } }
留意すべきは、メソッドの引数リストにある this キーワードです。これは、拡張メソッドを適用する型を指定するもので、この例の場合は、IEnumerable<T> オブジェクトになっています。2 番目の引数は、実際にメソッドに渡すパラメータです。
次のコードは、Where メソッドを呼び出す例です。
IEnumerable<string> query = Enumerable.Where(names, s => s.Length < 6);
しかし、拡張メソッドでは次のようなインスタンス構文を使用しても呼び出すこともできます。つまり、あたかも IEnumerable<T> オブジェクトに Where メソッドが存在するかのように使うことができます。これが、「拡張」と呼ぶ由来です。
IEnumerable<string> query = names.Where(s => s.Length < 6);
式ツリーは、"expression tree" にあてた訳語ですが、その正体がどうもよく分かりません。"expression" は、System.Linq.Expressions 名前空間内にある Expression クラスおよびそれから派生するクラスをあらわすことは間違いないと思いますが、問題は「ツリー」です。
.NET Framework SDK によると、式ツリーとは、実行コードをデータ構造に変換したものということです。特に、LINQ クエリ式のような C# コードを SQL データベースなどの別のプロセス上で操作するコードに変換したいときに有効だとあります。では、データ構造とツリーとがどういう関係にあるのかですね。
Microsoft のサイトにおいて、"Expression Tree Visualizer" というアプリケーションが公開されています。Visual Basic のソースファイルも付いていますから利用しやすいと思います。ダウンロード先は Tools のページに書いておきました。下図は、次のコード(式)のツリー構造を表示したところです。
Func<int,int,int> function = (a, b) => a + b;
つまり、System.Linq.Expressions 名前空間内にある Expression クラスおよびそれから派生するクラスを使って作成するデータ構造をツリー状に構成するので、それを総称して「式ツリー」と呼ぶのだろうと思います。式ツリーは内部的な問題なので、アプリケーション開発者が意識する必要はありません(断言していいのなかあ?)。
いずれにしろ、式ツリーという言葉が SQL 用語の中にあるのかどうかは知りませんが、SQL との関連性が深いようには思います。あるいは、SQL のために作ったものなのかもしれません。
LINQ クエリは単なるスクリプトですから、コードをコンパイルするとき、.NET Framework の実装メソッドに変換します。それらを「標準クエリ演算子 "Standard Query Operators"」と呼びます。
標準クエリ演算子の実装は、Enumerable<T> クラスまたは Queryable<T> クラスの各メソッドです。演算子という呼び名に違和感がありますが、LINQ の思想の中にメソッドという概念がないので、「演算子」にしたと理解するほかありません。
ところで、標準クエリ演算子の「標準」には特別な意味があって、.NET Framework が提供するものが「標準」です。つまり、LINQ の作法に則っている限り、独自のクエリ演算子を定義することができます。たとえば、先に説明した LINQ to Objects や LINQ to XML がクエリ演算子の拡張の例です。
詳しくは、「標準クエリ演算子」のページをご覧ください。
射影または投影 "projection" は、LINQ 用語の中でもっとも奇妙な言葉ですが、SQL 用語の延長線上にあるもののようです。私は「選択」と理解しておいてもおおむね間違いではないと考えています。
遅延実行 "deferred execution" は、メソッドを呼び出した時点で実行するのではなく、その結果を操作したときに実行することです。結果の操作とは、結果(通常は IEnumerable インターフェースを継承するオブジェクト)に対して foreach ステートメントを適用するようなケースをさします。なお、プログラミング上、遅延実行するかどうかを意識する必要はないと思います。
NETClass は、XML および LINQ に関係するクラスライブラリリファレンスです。詳しくは、Software のページをご覧ください。
−以上−