C# - 引数 - 値渡しと参照渡し
メソッドの引数を参照渡しで行う場合は、仮引数だけでなく、実引数側にも ref をつける。これはメソッドの引数にしたことで、メソッド側から書き換えが発生する可能性のあることを明示する為である。
メソッドの結果を引数経由で呼び出し側に渡す用途の場合は、ref の代わりに out を使用する。このため呼び出し側で out を付けて渡す実引数は必ず変数でなければならない。またメソッド側から代入が行われるので値が未定の(代入していない)変数も使用できる。代わりにメソッド内では、outを付けた仮引数を読み出すことはできない。
参照型変数を参照渡しでメソッドに渡して、メソッド内において新規オブジェクトを代入(参照)した場合、呼び出し側の変数においても新規オブジェクトが参照され、元々参照していたオブジェクトを参照しなくなるので注意。
C# - 引数 - 規定値/名前付き引数/可変長引数
メソッド定義の仮引数に規定値を付けると、メソッド呼び出し時にその引数を省略することができる。ただし仮引数の並びで、規定値有りの引数の後ろに規定値無しの引数を置くことはできない。
また、メソッド呼び出し時に
仮引数名 : 値
とすることで仮引数の順番に関係なく値を渡すことができる。
更に、仮引数にparamsし配列を置くことで可変長の値を受け取ることができる。可変長引数に渡す値がなくてもエラーにならない。ただし可変長引数は、仮引数リストの最後に置かなければならない。
params 型[] 可変長仮引数名
続きを読む
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などのデリゲート型だけを使用すれば良いが、面白いのは複数のメソッドやラムダ式を格納できること。
デリゲート型 変数名 = メソッド名; 変数 += ラムダ式; 変数 -= メソッド;
名前がついているメソッドの場合は削除することもできる。この変数に引数リストをつけて実行すると、格納したメソッドやラムダ式が格納順に実行される。
変数(引数リスト);
ただし戻り値のあるデリゲート型の変数の場合は、最後に登録したメソッドやラムダ式の戻り値のみが、全体の戻り値として返される。このため登録した全てのメソッドやラムダ式の戻り値を取得したい場合は、コレクションを引数にして処理結果を追加し、それを戻り値とする様な方法にする必要がある。(もっと適切な方法があるかも……)
続きを読む