doridoridoriand’s diary

主に技術的なことを書いていく予定(たぶん)

C#のyieldに関して

まあなんか書くことなかったんだけど笑 C#のyieldを目にする機会が多かったので、ちょっと調べてみました。Microsoftのドキュメントを読んでみると

ステートメントで yield キーワードを使用した場合、メソッド、演算子、または get アクセサーが反復子であることを示します。 yield を使用して反復子を定義すると、カスタム コレクション型の IEnumerable および IEnumerator パターンを実装するときに明示的な余分なクラス (列挙の状態を保持するクラス。たとえば IEnumerator を参照) が不要になります。

フーン

まあコード書いてこのyieldの利益をえてみましょう。まずyieldを使っていない書き方から

class YieldTest {
  static void Main(String[] args) {
    foreach (var item in GenDataset()) {
      Console.WriteLine(item);
    }
  }

  static List<String> GenDataset() {
    List<String> dataset = new List<String>();

    for (int i = 0; i < 100; i++) {
      dataset.Add(i.ToString());
    }
    return dataset;
  }
}

まあ単純に0から99までの数字を配列に入れているだけです。次にyieldを使った書き方に変更してみます

class YieldTest {
  static void Main(String[] args) {
    var dataSet = GenDataset();
    foreach (var item in dataSet) {
      Console.WriteLine(item);
    }
  }

  static IEnumerable<String> GenDataset() {
    for (int i = 0; i < 100; i++) {
      yield return i.ToString();
    }
  }
}

ListからIEnumerableというインターフェースに変更して、かつ内部のListの変数宣言などが不要になっています

正直この例だと簡単過ぎてメリットを感じないのですが笑

ここでメソッドから帰ってきた配列の型を確認してみましょう。普通に書いた方は System.Collections.Generic.List1[System.String]`

ですが、yieldで書いた方は YieldTest+<GenDataset>c__Iterator0

という形で返ってきています。イテレータとなっていることから、List型ではなく、反復子として処理されたことがわかります。なので、内容はList型のような参照を行うことが出来ません(配列要素をカウントするCountなどをメソッドチェインすることは不能です)

。。結論として何を言いたいんだって感じになってしまいましたが、まあRubyにもYieldあったなあって思って色々試しただけですw

久しぶりにまとまらない話になりましたorz