概要
何番煎じか分かりませんが、***イテレータパターン(Iterator Pattern)***のお話です。
**C#**においては、言語に組み込まれていると言って良いでしょう。
Iterator パターン @ Wikipediaのクラス図に合わせた形で、C#の機能を説明していきます。
型
Aggregate -----------------> Iterator
△ △
│ │
Concrete Concrete
Aggregate -----------------> Iterator
IEnumerator<T>
デザインパターンで出てくるIterator
インタフェースは、C#では**IEnumerator<T>
**に当たります。
『列挙する者』みたいな意味(Enumurate + -or)ですね。
Current
,MoveNext()
next()
,hasNext()
は、C#では**Current
,MoveNext()
**のように少し違った形で実装されます。
interface IEnumerator<out T> {
// 現在の要素を取得する。
T Current { get; }
// 次の要素に移動する。次の要素があればtrue,無ければfalseを返す。
bool MoveNext();
// その他の定義は省略
}
IEnumerable<T>
デザインパターンで出てくるAggregate
インタフェースは、C#では**IEnumerable<T>
**に当たります。
『列挙可能』みたいな意味(Enumurate + -able)ですね。
GetEnumerator()
iterator()
メソッドは、C#では**GetEnumerator()
**に当たります。
interface IEnumerable<out T> {
// イテレータを取得
IEnumerator<T> GetEnumerator();
// その他の定義は省略
}
IEnumerable<T>
を実装した型
ConcreteAggregate
に当たるC#の型は無数にあります。
同一の型のインスタンスを複数扱うようなデータ型はほぼこれに当てはまると思って良いでしょう。
- 配列
List<T>
Dictionary<TKey,TValue>
IEnumerator<T>
を実装した型
IEnumerator<T>
を実装した型は、例えばList<int>.Enumerator
型などがあります。
ただ、こちらは実装型を意識せずに利用することが普通ですね。
組み込まれている機能
foreach構文
foreach構文では、GetEnumerator()
メソッドを持つインスタンスであれば、同一の構文で要素を列挙できます。
これはC#プログラマなら無意識レベルで使っているであろう例です。
foreach (var item in obj) {
Console.WriteLine(item);
}
↑の構文は↓とほぼ同義になります。
var iterator = obj.GetEnumerator();
while (iterator.MoveNext()) {
Console.WriteLine(iterator.Current);
}
// 実際には例外処理や後処理などがあるが、ここでは省略
LINQ
LINQ to Objectでは、IEnumerable<T>
を『流れるようなインタフェース』として扱うことで、様々な標準クエリを利用可能にしています。
Enumerable
.Range(3, 10)
.Where(i => i % 2 == 1)
.Select(i => new { A = i, B = i * i / 2, C = i * i / 2 + 1 })
.ToList()
.ForEach(Console.WriteLine);
ジェネレータ
C#ではIEnumerable<T>
を利用したイテレータを生成するための構文が用意されています。
自前でIEnumerable<T>
とIEnumerator<T>
を作成する手間は基本的に不要と言えます。
(少しややこしいのですが、この構文は"Iterator block"と呼ばれます。)
// イテレータ構文と呼ばれているが、実際にはジェネレータ
static IEnumerable<int> Generate5Primes() {
yield return 2;
yield return 3;
yield return 5;
yield return 7;
yield return 11;
}
// 無限ループも使い方次第
static IEnumerable<double> RandomDoubles() {
var random = new Random();
while (true) {
yield return random.NextDouble();
}
}
まとめ
"Gang of Four"によるデザインパターンの紹介が1994年のことになります。つまり、C#に限らずその後にリリースされた言語ではこれらのデザインパターンが言語に取り込まれていることも多いのです。
これからデザインパターンを勉強しようとしている人は、自分の得意とする言語(やフレームワーク)にどのようなデザインパターンが組み込まれているのかを調べてみると良いと思います。