|
|
連載:[完全版]究極のC#プログラミング
Chapter15 LINQとクエリ式
川俣 晶
2010/03/17 |
|
|
15.6 LINQの本質は列挙
さて、この例を見て何の意味もないプログラムだと思った読者もいるだろう。だがそうではない。このプログラムは、次のプログラムと比較することで、LINQの重要な性質を明らかにできるのである。ではその話題に進もう。
先ほど「LINQを使って記述できる処理は、LINQを使用しなくても書くことができる。foreach文で繰り返しを行えばよい」と書いた。そこで、前節の例を、LINQではなくforeach文で書き直してみよう(リスト15.3参照)。
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3 };
var list = new List<int>();
foreach (int n in array) list.Add(n); // クエリ式を置き換えた行
foreach (int n in list) Console.WriteLine(n);
// 出力:
// 1
// 2
// 3
}
}
|
|
リスト15.3 リスト15.2のクエリ式をforeach文に置き換えた |
この2つのプログラムの動作は、使用されるコレクションの種類などの瑣末な問題を除けば、同じといってよいのだろうか? つまり、
var query = from x in array select x;
|
|
を、
var list = new List<int>();
foreach (int n in array) list.Add(n);
|
|
に置き換えて、つねに同じ結果が得られると期待してよいのだろうか?
実はそうではない。たった1行追加するだけで、その差を見ることができる(リスト15.4、次ページリスト15.5参照)。
static void Main(string[] args)
{
int[] array = { 1, 2, 3 };
var query = from x in array select x;
array[1] = 4; // 追加行
foreach (int n in query) Console.WriteLine(n);
// 出力:
// 1
// 4
// 3
}
|
|
リスト15.4 クエリ式版(リスト15.2)に1行追加(抜粋) |
static void Main(string[] args)
{
int[] array = { 1, 2, 3 };
var list = new List<int>();
foreach (int n in array) list.Add(n);
array[1] = 4; // 追加行
foreach (int n in list) Console.WriteLine(n);
// 出力:
// 1
// 2
// 3
}
|
|
リスト15.5 foreach版(リスト15.3)に1行追加(抜粋) |
見てのとおり、1行書き加えただけで、結果は違ってしまった。値を書き換えた結果は、クエリ式版にのみ反映されている。なぜかといえば、foreach版がコレクションの複製を作成しているのに対して、クエリ式版は列挙を行うオブジェクトを作成しているという相違があるためだ。つまり、クエリ式版は列挙が行われるまで結果が何になるか確定しない。クエリ対象が変化すれば、列挙結果も変化する。
したがって、foreach版の動作をクエリ式版に近づけるには、コレクションを複写するのではなく、列挙インターフェースを取得して、それを変数に保存するとよい(リスト15.6参照)。実行されている機能はまったく異なっているが、少なくとも結果は同じになる。
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3 };
// 列挙インターフェースの取得
IEnumerable<int> enumerator = array;
array[1] = 4; // 追加行
foreach (int n in enumerator) Console.WriteLine(n);
// 出力:
// 1
// 4
// 3
}
}
|
|
リスト15.6 リスト15.2は本当はこれに近い |
Insider.NET 記事ランキング
本日
月間