C# - foreach文とyield
IEnumerable<T>型のメソッドを定義して、その処理中に yield return 値; を記述することで、IEnumerable<T>オブジェクトを生成することができる。
IEnumerable<int> MyEnumerable() { 処理; yield return 値; 処理; }
この方法を利用したほうが、IEnumerable<T>型やIEnumerator<T>型のクラスを定義するよりも簡単にEnumeratorが作成できる。
試しにforech文を使用せずに、GetEnumerator()メソッドでIEnumerator<T>型オブジェクトを取得したところ、GetNext()メソッドおよびCurrentプロパティで値を順番に取得することができた。
yield returnを使用した場合の動作は、IEnumerable<T>型のメソッド中でyield return文に出くわすと、foreach側に制御が移ってforeachブロックの処理を実行する。その処理が終了すると再びIEnumerable<T>型のメソッドに制御が移りyield return文の次から処理が行われるという形になる。これがIEnumerable<T>型のメソッドの処理が終了するまで継続する。
C# - foreach文とIEnumerableインターフェース(ジェネリック)
ジェネリックに対応させるには、昨日に対してIEnumerable<T>、IEnumerator<T>とIDisposableインターフェースを追加して継承する。
interface IEnumerable<T> { IEnumerator<T> GetEnumerator(); } interface IEnumerator<T> { T Current { get; } }
GetEnumeratorメソッドはIEnumerator<T>型オブジェクトを、CurrentプロパティはT型を戻り値とするため、追加の定義を行う。IEnumerator内でファイルオープン等を行う場合は、IDisposable.Disposeメソッドで破棄の処理を記述する。
C# - foreach文とIEnumerableインターフェース
foreach文において in の後に置けるオブジェクトはIEnumerableインターフェースを継承したクラスとなる。
IEnumerableは、GetEnumeratorメソッドでIEnumeratorオブジェクトを返す。
interface IEnumerable
{
IEnumerator GetEnumerator();
}
GetEnumeratorメソッドで返されたIEnumerableオブジェぅとは以下のプロパティとメソッドを持つ
interface IEnumerator { object Current { get; } void Reset(); bool MoveNext(); }
foreach文において、GetEnumeratorメソッドでIEnumeratorを取得し、そのMoveNextメソッドがtrueを返す間は、Currentプロパティを要素を取得してブロック内の処理を行う。
Currentプロパティに要素の取得前には必ずMoveNextメソッドが呼ばれるので、初期状態においては要素を指す内部インデックスは最初の要素の前を指している必要はある。
C# - デリゲート
デリゲートとは要するにラムダ式をいれるデリーゲート型変数を定義して使用する仕組み。
デリゲート型は以下のように定義する。
delegate 戻り値型 デリゲート型(引数型と引数名リスト);
あるデリゲート型で宣言したデリゲート変数は、その型で定義された戻り値と引数リストを持つメソッドやラムダ式を格納できる。
デリゲート型 変数名 = メソッド名; デリゲート型 変数名 = ラムダ式;
これだけだと、既に定義されているActionなどのデリゲート型だけを使用すれば良いが、面白いのは複数のメソッドやラムダ式を格納できること。
デリゲート型 変数名 = メソッド名; 変数 += ラムダ式; 変数 -= メソッド;
名前がついているメソッドの場合は削除することもできる。この変数に引数リストをつけて実行すると、格納したメソッドやラムダ式が格納順に実行される。
変数(引数リスト);
ただし戻り値のあるデリゲート型の変数の場合は、最後に登録したメソッドやラムダ式の戻り値のみが、全体の戻り値として返される。このため登録した全てのメソッドやラムダ式の戻り値を取得したい場合は、コレクションを引数にして処理結果を追加し、それを戻り値とする様な方法にする必要がある。(もっと適切な方法があるかも……)
続きを読むC# - ラムダ式とデリゲート型
処理をひとつの固まりとして扱うのがラムダ式。
(引数リスト) => {処理}; (引数リスト) => {処理; return 戻り値;};
引数がひとつの場合や、処理が単文の場合は括弧を省略できる。また処理が単文の場合はreturnも省略できる。
ラムダ式は、デリゲート型の変数や引数として扱うことができる。
デリゲート型には以下の様な種類がある。
Action型
値を返さない処理を扱う。
Action<引数の型リスト> 変数 = (引数リスト) => {処理};
Func型
値を返す処理を扱う
Func<引数の型リスト, 返り値の型> 変数 = (引数リスト) => {処理; return 戻り値;};
Predicate型
引数について処理を行った結果のbool値を返す
Predicate<引数の型> 変数 = (引数) => { 処理; return bool値; };
Comparison型
2つの引数の大小の判定を行う。int値を返す。
- 処理結果 < 0 : xがyより小さい
- 処理結果 == 0 : xとyは等しい
- 処理結果 > 0 : xがyより大きい
Comparison<引数の型> 変数 = (x, y) => { 処理; return int値; };
C# - コレクション - List<T>
配列のコレクション版。
< T >の部分に型を指定してnewを行うことで、その型のコレクションとなる。