連載:[完全版]究極のC#プログラミングChapter3 新しい繰り返しのスタイル ― yield return文とForEachメソッド川俣 晶2009/08/31 |
|
|
3.4 C# 3.0によるRangeクラスの実装
この2つのうっとうしさは、C# 3.0の反復子の機能を使って書き直すと、きれいさっぱり消えてなくなる。
ともかく、圧倒的にスリムになったコードを見ていただきたい(リスト3.2参照)。
| |
リスト3.2 C# 3.0によるRangeクラスの実装 |
このように、2つ必要だったクラスは1つになり、MoveNextメソッド、Currentプロパティは消滅し、状態を記憶しておくフィールドは単なるローカルなループ変数へと立場を大幅に後退させてしまった。
この程度のコード量であれば、気軽に列挙可能なオブジェクトを作ろう……という気にもなるだろう。
さて、どのような構文がこの劇的な変化をもたらしたのだろうか?
C# 3.0版で目新しい構文は、「IEnumerator<int>」と「yield return i;」しかない。このうち、前者はC# 1.xからあるIEnumerableインターフェース(System.Collections名前空間)のジェネリック版にすぎないので、型が明示されたことを除けばなんら目新しいことはない。
つまり、注目ポイントは「yield return i;」だけである。ところが、このたった1つの文がすべてを劇的に変えてしまうのである。
実は、「yield return文」と、後で紹介する「yield break文」を含むブロックは、通常のブロックではなく「反復子ブロック」というものになる。
つまり、リスト3.2内の次のブロックは、反復子ブロックになるのである。
|
反復子ブロックは通常のブロックとは異なり、すぐには実行されず、その代わりに列挙子オブジェクトというものが生成される。
ソースコード上に書かなくてよくなったクラス(リスト3.1のRangeEnumクラスのようなクラス)に相当するクラスが自動的に用意され、そのインスタンスが作成されるのである。その作業はC#プログラマーからは見えない水面下の部分で自動的に行われる。
しかし、そのような詳細を知る必要はない。foreach文で使うとすれば、C#プログラマーが知る必要があるのは、次のことだけである。
- 反復子ブロックはすぐには実行されない
- 実行されるのはforeach文で列挙が開始された後である
- 反復子ブロック内でyield return文が実行されると、その引数の値がforeach文に渡り、文が1回実行される
- foreach文に指定された実行文(リスト3.2ではConsole.Writeメソッド)の実行が終わると、反復子ブロック内の続きが実行される
ここで注意が必要なのは、yield return文は、return文と同じように記述し、同じように値を呼び出し側に返すが、呼び出し側の処理が一段落するとその続きが再度実行されるという点である。
たとえば、次ページのリスト3.3には2つのyield return文が存在するが、これらは双方とも実行される。最初のyield return文で終わってしまうわけではない。一時的に呼び出し元に実行権を譲るだけである。
| |
リスト3.3 実行継続されるyield return文の確認 |
実行結果を見るとわかるとおり、foreach文で指定された実行文と反復子ブロック内の文は交互に実行される。このような実行形態はあまり例がなく、一見わかりにくいかもしれない。しかし、それによってソースが短くなり、コーディングの負担も減り、楽ができるわけである。楽ができる以上は、正しく理解するために努力する価値がある。
INDEX | ||
[完全版]究極のC#プログラミング | ||
Chapter3 新しい繰り返しのスタイル ― yield return文とForEachメソッド | 1.3.1 「繰り返し」という古くて新しい問題 | |
2.3.2 数を数えるというサンプル | ||
3.3.3 C# 1.xによるRangeクラスの実装 | ||
4.3.4 C# 3.0によるRangeクラスの実装 | ||
5.3.5 yield break文による中断 | ||
6.3.6 yieldは予約語ではない | ||
7.3.7 1つのクラスに複数の列挙機能を付ける | ||
8.3.8 自動的に作られるオブジェクトと二重利用 | ||
9.3.9 catchできない制約 | ||
10.3.10 制約の真相―見た目と違う真実の姿 | ||
11.3.11 ForEachメソッドを使う別解 | ||
12.3.12 性能比較 | ||
「[完全版]究極のC#プログラミング」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|