(鳥山 隆一=TRO)

著者紹介
 IT関連ライター。プログラミングから,IP電話,企業におけるシステム導入まで,IT関連で幅広く活躍。2003年に企業のシステム導入事例の作成を業務の中心とする有限会社TROを設立。IT関連企業の導入事例を多く手がけている。
 今回はVisual Studio 2005(C# 2.0)で新たに強化された言語仕様の1つであるIterators(イテレータ)について説明しよう。前回説明したGenerics(ジェネリクス)と同様に,Javaには既に実装されている機能だ。もちろんC++にも実装されている。英単語のIterateとは「反復適用する」という意味であり,Iteratorsは“反復子”とか“列挙子”と呼ばれている。ただし,列挙子と言った場合はEnumeratorを指すことが多く,誤解を避けるため邦訳せずに,Iteratorsとそのまま呼ぶのが普通だろう。

繰り返し処理を容易に実現する
 Iteratorsは,「反復適用」という意味からも想像できるだろうが,特定の集合の要素を順番に1つずつ取り出して,何らかの処理を加えるための仕組みである。順番に1つずつ,という言葉からforeach文が思い浮かぶかもしれない。実際,Iteratorsは多くの場合,foreach文と組み合わせて使う。

 ここで,Iteratorsを理解しやすくするためにforeach文を思い出してみよう。例えば文字列配列の中身を順に取り出して表示するコードは以下のようになる。

string[] A = {"Visual","Studio","2005"};  //文字列の配列を定義
foreach (string s in A)                     //配列の中身を順番に取得する
{
    System.Console.WriteLine(s);            //取得したものを表示
}

 実行結果は次のようになる。

Visual
Studio
2005

 これは,文字列配列がforeach文で呼び出されたときに,列挙できるようになっているためである。文字列配列のように,foreach文を使って要素を列挙できるようなクラスを作るための仕組みがIteratorsである。

 具体的には,IEnumerableインターフェースを継承してクラスを定義する。例えば次のようなコードになる。

public class List : IEnumerable
{
    public IEnumerator<string> GetEnumerator()
    {
        yield return "Visual";
        yield return "Studio";
        yield return "2005";
    }
}
 : IEnumerable

 要素を1つずつ返すには,このようにGetEnumeratorメソッドをオーバーライドし,そのメソッド内でyield return文を使って要素を返す。実際にこのListクラスの要素を,foreach文で列挙するコードは次のようになる。

List list = new List();
foreach(string s in list)
{
    Console.WriteLine(s);
}

 実行結果は,先に挙げた文字列配列の要素を列挙したときと同一になる。例えば,これをyield returnを使わずに実装しようとすると,どこまで取り出されたのかを記録するポインタの役割をする変数が必要になる。オブジェクトの状態を記録しておく処理は,それ自体コーディングが面倒だし,クラスの仕様変更時には大幅にコーディングし直さなくてはならなくなることもある。こうした作業ではミスが発生しやすく,バグの原因にもなることも多かった。Iteratorsを使うことで,これらが不要になり,コードの品質を高められる。

 この例では,文字列を返しているが,前回説明したGenericsを使って,変数の型を特定しないクラスも定義できる。例えば,以下のような,列挙可能なクラスも作成できる。

public class Stack<Type> : IEnumerable
{
    Type[] buff;    //要素を格納する変数
    int pointer;      //現在の位置
    public Stack(int max)
    {
        this.buff = new Type[max];    //要素の数を決める
        this.pointer = 0;               //先頭に移動
    }

    public void AddItem(Type item)    //要素を追加するメソッド
    {
        this.buff[this.pointer++] = item; //配列に要素を追加
    }

    public IEnumerator<Type> GetEnumerator()
    {
        for (int i = 0; i < this.pointer; i++)    //(1)
        {
            yield return buff[i];    //呼び出された順に,要素を返す
        }
    }
}
 : IEnumerable

 このStackクラスは,以下のようにして利用できる。ここでは文字列を格納したが,もちろん数値型などの値も扱える。

Stack<string> slist = new Stack<string>(3);
slist.AddItem("Technology");
slist.AddItem("Report");
slist.AddItem("Office");

foreach (string s in slist)
{
    Console.WriteLine(s);
}

 列挙するときに,値を返す順番は,クラスの定義時に自由に変更できる。上記の場合,格納した順番で,そのまま取り出されることになるが,例えばリスト中(1)の部分を以下のように書き換えることで,後から格納したものから先に取り出せるようになる。

for (int i = this.top - 1; i >= 0; --i)

 もちろん,格納した順番と逆の順に取り出すというだけでなく,返す値や返す順序はコードの内容によって自由に変更できる。Iteratorsを使えるようになったため,foreach文によって列挙できるクラスが非常に簡単に作れるようになったといえる。

 今回は,C# 2.0によって新しく実装された,列挙に対応したクラスを作るためのIteratorsを説明した。残念ながら,Visual Studio 2005の新機能についての連載は今回をもって一度終了する。しかし,紹介すべき機能は言語仕様などだけでなく,開発ツール自体の画面レイアウトやテスト機能,リファクタリング,チーム開発に関する機能など,非常に広範に及んでいる。ぜひ,どれほど進化しているか,自身で触って体感してもらいたい。