2009年11月14日

【yield】 foreach文を途中でbreakするには?

yield句について最初から読みたい方はこちらからどうぞ。
今回は、foreach文を中断する為の構文、yield breakについて解説します。
といっても簡単なので早速以下のコードを御覧ください。
class BreakableClass
{
    public IEnumerator<int> GetEnumerator()
    {
        for (int i = 0; i < 10; i++)
        {
            if (i == 5)
            {
                // iが5になったらループを抜ける
                yield break;
            }

            // ループカウンタの値を返す
            yield return i;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var breakClass = new BreakableClass();
        foreach (int n in breakClass)
        {
            Console.WriteLine(n);
        }
    }
}
//<処理結果>
0
1
2
3
4
本来、yield breakが無い場合は0〜9までの数字が表示されるはずですが、
ループ変数iが5になった時に、ループ処理を打ち切っているので
0〜4まででforeach文が終了します。
つまり、yield break文でforeachを中断する処理を書けるという訳です。

ラベル:yield
posted by 吾一 at 17:33| 4. yield return | このブログの読者になる | 更新情報をチェックする

2009年11月08日

【yield】 CSVファイルを縦列毎に列挙する

今回は、yield returnの実践例を紹介します。
CSVファイルを行毎に列挙するサンプルコードは、@ITのこちらで公開されていますが、
これを少し改造してCSVファイルを縦列毎に列挙するサンプルコードを作成しました。

以下にサンプルで使用したCSVファイルの内容を示します。
gamehard.csv」の内容


続いて、実際のコードです。
class CsvParser
{
    // CSVファイルのパス
    private string filePath;

    // コンストラクタ
    public CsvParser(string path)
    {
        filePath = path;
    }

    // foreach可能なメソッド
    public IEnumerable<string> GetColumns(int idx)
    {
        // CSV Parserを使用( TextFieldParserは「using Microsoft.VisualBasic.FileIO」と参照設定が必要 )
        using (var parser = new TextFieldParser(filePath, Encoding.GetEncoding("Shift_JIS")))
        {
            parser.TextFieldType = FieldType.Delimited;
            parser.SetDelimiters(","); // 区切り文字はコンマ=CSV形式

            while (!parser.EndOfData)
            {
                // 1行読み込み
                string[] row = parser.ReadFields();
                // N列目のカラムを返す
                yield return row[idx];
            }
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        // CSVファイルのカラム数分ループしている(すべての列を順に列挙)
        for (int i = 0; i < 5; i++)
        {
            // CSVファイル名を指定
            var csv = new CsvParser("gamehard.csv");

            // CSVファイルの特定の縦列を列挙する
            foreach (string col in csv.GetColumns(i))
            {
                Console.WriteLine(col);
            }
        }
    }
}
//<出力結果>
//1
//2
//3
//4
//5
//ファミリーコンピュータ
//スーパーファミコン
//セガサターン
//プレイステーション
//Xbox
//1983年7月15日
//1990年11月21日
//1994年11月22日
//1994年12月3日
//2002年2月22日
//任天堂
//任天堂
//セガ・エンタープライゼス
//ソニー・コンピュータエンタテインメント
//マイクロソフト
//14800円
//25000円
//44800円
//39800円
//34800円
ループでCSVファイルの1〜5列目を順番に出力しています。
foreach文に指定しているGetColumnsメソッドの引数で、何列目を列挙するかを指定出来るようにしています。
yield returnを使用することで、簡単な構文でforeachを可能にしています。
CSVの列を縦に列挙する事があるかは疑問ですが、yieldの使い方を覚えておけばいざという時に役に立つかもしれません。

ラベル:yield
posted by 吾一 at 00:06| 4. yield return | このブログの読者になる | 更新情報をチェックする

2009年11月01日

【yield】 foreach可能なクラスを作るには?

今日からは、また新しい章に入ります。
今回はyield return文について解説します。
yield returnを使用することで、foreachで列挙可能な自前のクラスを作ることが出来ます。

Q. foreachで列挙可能なクラスを作るには?
A. IEnumerator<T>を返す、GetEnumeratorという名前のメソッドを作る
これだけです。interfaceは実装しなくても良いみたいです。

では、IEnumerator<T>型とは何者なのか?
この型が今回解説するyield returnと深い関係にあります。
yield returnとはreturnが付いてる事から分かるように、戻り値を返す文です。
ただし、若干普通の処理の流れとは違う部分があるので、慣れが必要です。
以下のコードを御覧ください。
class EnumerableClass
{
    public IEnumerator<int> GetEnumerator()
    {
        Console.WriteLine("チェックポイント1");
        yield return 1;

        Console.WriteLine("チェックポイント2");
        yield return 2;

        Console.WriteLine("チェックポイント3");
        yield return 3;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 列挙可能なオブジェクト
        var enumerable = new EnumerableClass();
        foreach (int ret in enumerable)
        {
            Console.WriteLine("foreach {0}周目の戻り値", ret);
        }

        // <結果>
        // チェックポイント1
        // foreach 1周目の戻り値
        // チェックポイント2
        // foreach 2周目の戻り値
        // チェックポイント3
        // foreach 3周目の戻り値
    }
}
EnumerableClassがforeach可能なクラスです。
foreachでGetEnumerator()をコールしますが、yield return 1;まで実行したとこで一旦処理がMainメソッドに戻り、foreach内の処理が1回実行されます。
次に呼ばれた時は、前回yield returnした箇所の続きから実行することになります。(2周目はyield return 2;まで実行)
foreach1周毎に次のyield returnまで実行するということですね。
foreachとGetEnumerator()を交互に実行しているイメージを持つと分かりやすいかと思います。

処理の流れが掴み辛いですが、自前でforeach可能な文が手軽に作れるというのは結構便利です。
次回は、もう少し実践的で使えそうなサンプルコードを考えてみたいと思います。
ラベル:yield
posted by 吾一 at 21:48| 4. yield return | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。