クエリの書き方以外にもいくつか押さえておく点があります。
■クエリの戻り値はIEnumerable<T>オブジェクト
クエリの戻り値は、クエリの最後がselect句の場合にはIEnumerable<T>インターフェイスを実装したオブジェクトとなります。実際には公開されていないクラス・ライブラリ内のクラスのオブジェクトなのですが、それがどのようなクラスかについて開発者は気にする必要はなく、そのクラスがIEnumerable<T>インターフェイスを実装しているという点のみがポイントです。
先ほども述べたように、IEnumerable<T>インターフェイスを実装しているということはforeach文により列挙できます。つまり、クエリの結果はforeach文で利用されることが前提となっているわけです。
■遅延実行
もう1点、LINQを使ううえで気を付けなければならないことは、クエリの戻り値を変数に代入しただけではクエリは実行されないという点です。便宜上、ここまでクエリの戻り値(出力)を「クエリ結果」と記述していましたが、このクエリ結果には実際にはクエリの結果は格納されません。
クエリが実行されるのは、クエリの結果がforeach文により処理されるときなのです。これは「遅延実行(deferred execution)」と呼ばれます(「defer」は「延期する」「延ばす」という意味)。
サンプル・プログラムで確認してみましょう。次のプログラムは1〜40の数字のうち3の倍数と3が付く数字のみを抽出するクエリを作成しています。そしてforeach文にその結果を列挙し画面に表示します。その後、10以降の数字をすべて「1」に変更し、もう一度foreach文を実行します。それらの出力の違いから、クエリを作成した時点ではクエリは実行されていない(クエリの結果が固定的でない)ことが分かります。
using System;
using System.Linq;
class Nabeatsu {
static void Main() {
// 1から40までの配列numsを作成
int[] nums = Enumerable.Range(1, 40).ToArray();
// 3の倍数と3が付く数字のみを抽出
IEnumerable<int> result =
from n in nums
where n % 3 == 0 || n.ToString().Contains("3")
select n;
foreach (int num in result) {
Console.WriteLine(num);
} // 出力: 3、6、9、12、13、15、18、21、23、24、27、30、……
// 「10」以降をすべて1に変更する
for (int i = 10; i < nums.Length; i++) {
nums[i] = 1;
}
foreach (int num in result) {
Console.WriteLine(num);
} // 出力: 3、6、9
}
}
これは「LINQ to Object」での例ですが、「LINQ to SQL」の場合にはforeach文を実行したときに初めてSQL文がデータベース・サーバに送信されるということが遅延実行により起こります。
このため、foreach文を実行するたびにデータベースの最新のレコードを得ることができます。逆に、foreach文を実行するまでは何度でもクエリを実行できます(何度実行しても無駄なSQL文が発行されることはありません)。
とはいっても遅延実行されると困る場合もあります。そのような場合には、クエリ結果に対してToArrayメソッドあるいはToListメソッドを呼び出せば、クエリが即時実行され、配列あるいはList<T>オブジェクトが作成されます。
今回の最後に、LINQ学習用のフリーのツールを紹介しておきます。「LINQPad」というツールです。ダウンロードは以下のページから行ってください。
このツールでは、LINQのクエリだけを簡単に実行して試すことができます。クエリ対象がデータベースであっても非常に簡単です。クエリの実行結果は見やすい表形式で表示されます。
しかもLINQPadにはクエリのサンプルも数多く組み込まれており、簡単に試していくことができます。非常によくできた学習ツールです。
今回はLINQの基礎について解説しました。次回はもう少し掘り下げつつ、LINQ to SQLを使ったLINQについて解説していきます。
Copyright© Digital Advantage Corp. All Rights Reserved.