i-school - デリゲートとラムダ式の関係

ラムダ式と匿名関数


 ラムダ式は、ラムダ演算子を用いて簡潔に関数を表現するための機能です。

 ラムダ式を使うことで、匿名関数(名前のないメソッド)を作成し、メソッドの本体を直接記述することができます。
また、ラムダ式を使用することで、引数や戻り値の型を自動的に推論することができます。

 より簡単ないい方をすると、事前に定義してあるメソッドを実行するのではなく、
その場でメソッド内の処理を作成して実行させることができる機能です。そのため、メソッド名がありません。

 これにより、コードがシンプルで読みやすくなります。

参考サイト
MicroSoft
ラムダ式と匿名関数
MicroSoft
ラムダ式演算子はラムダ式を定義する
Qiita @toRisouP(株式会社 バーチャルキャスト) 様
【C#】わかった"つもり"になれる「ラムダ式」解説


ラムダ式の書式


 ラムダ式は最初に説明したように、メソッドを省略して記述できる記法です。

 ラムダ式は、ラムダ演算子 => を利用し、アクセス修飾子、メソッド名、戻り値の型、引数の型を省略した上で、引数と処理のみを記述します。

 引数と戻り値については、ラムダ式では型推論の機能が自動的に備わっているため、
変数名だけを宣言すればよい(処理の内容を元に、プログラム側で型を自動的に認識)することになります。
(C# における式書式には return が自動的につくため、必ず void 以外の戻り値を持つことになります。)

 型は省略されていますが、任意の変数名をつけることが出来ます。



 下記の記述が、アクセス修飾子、メソッド名、戻り値の型、引数の型を省略した上で、引数用の変数と処理のみを記述した、ラムダ式によるメソッドの書式です。

(引数) => { 処理 }

 別の書き方をすると、下記のような意味になります。

(引数の変数) =>  {メソッドの中身(処理)}



<例>

 上記の書式になぞらえて、メソッドをラムダ式で記述した処理の例です。

 (x, y) => { return x + y; }

 このような書式でメソッドを作成することができます。

 では、これはいったいどのような処理なのでしょうか?
メソッドがどのようにして省略されてここに至るのか、順番に過程を解説します。



 下記のようなメソッドがあったとします。

 このメソッドの引数と処理の内容が、上記のラムダ式で利用されている部分になります。
なぜなら、ラムダ式では引数と処理だけを書けばメソッドとして認識されるためです。
 
private int CalSum( int x , int y)
{
   return x + y;
}

  ↓
 
 上記の処理を省略して記述することで

 (x, y) => { return x + y; }

 こうなります。

 では、最初のメソッドを、少しずつラムダ式に近づけていきます。



 まず、メソッド内の処理の内容を横に移動します

private int CalSum( int x , int y) { return x + y; } // ← ここに移動

 続いて、アクセス修飾子を省略します。
ラムダ式は引数や変数に格納して使うので、アクセス修飾子は不要です(常にローカル扱いです)

  ↓

private int CalSum( int x , int y) { return x + y; }


 こうなりました。

int CalSum( int x , int y) { return x + y; }

 ここでラムダ式の記法に変更することで、関数名を省略します
また、戻り値と引数が型推論になるため、戻り値と引数の型の宣言を省略します


int CalSum(int x , int y) { return x + y; }

  ↓

 こうなりました。

(x,y) => {return x + y;}

 これで最初に提示したラムダ式の処理の完成です。
残っている左辺の (x, y) が引数の変数、右辺がメソッド内の処理の内容です。

 ラムダ式は読み解くことが非常に難しいため、最初のうちは、このように1つ1つ処理の流れを分解して理解を深めていくようにしてください。


デリゲートと匿名メソッド


 デリゲートは、C# の関数ポインタのようなもので、他のメソッドを参照する変数の型です。
簡単に言えば、デリゲートはメソッドを変数のように扱うことができる仕組みです。これにより、メソッドを引数や戻り値として渡すことができます。

 こちらの記事も参考にしてください。

 → デリゲート

 匿名メソッドは、名前を持たない関数で、デリゲートを使って処理を渡す際に使われます

 つまりラムダ式は、この匿名メソッドを使い、デリゲートの機能を使うことで、簡潔に記述することができる仕組みです。


デリゲートとラムダ式の関係


 デリゲートとラムダ式は、両方ともメソッドに関連する概念ですが、
いままでの説明ことから、その関係は以下のようにまとめられます。

 ・デリゲートは、メソッドへの参照を保持するオブジェクトです。
 ・ラムダ式は、匿名関数を簡潔に定義するための構文です。
 ・ラムダ式で定義した匿名関数は、デリゲートに代入して使います。

 よってラムダ式は、デリゲートを使ってコードを短く書くために利用されているとも言えます。


デリゲートとラムダ式を使った実装例


 以下に、デリゲートとラムダ式を使った例を示します。


// デリゲートの宣言
public delegate bool MyPredicate(int value);

// デリゲート型の変数にラムダ式で定義した匿名関数を代入
MyPredicate isEven = n => n % 2 == 0;

// デリゲートを使ってメソッドを呼び出す
bool result = isEven(4); // 結果は true

 この例では、MyPredicate というデリゲートを定義し、isEven という変数にラムダ式で定義した匿名関数を代入しています。
この匿名関数は、与えられた数値が偶数かどうかを判断します。

 デリゲートを使って、この匿名関数を呼び出すことができます。この例では、isEven(4) として、4 が偶数であるかどうかを判断しています。

 このように、ラムダ式を使って、見えないメソッドが存在し、その中に処理を書き込んで実行することができます。


匿名メソッドとラムダ式の違い


 匿名メソッドとラムダ式は、両方とも名前を持たないメソッドを定義する方法ですが、書式が異なります。
以下に、それぞれの書式を示します。


1.匿名メソッド



delegate(引数) { 処理 }


2.ラムダ式



(引数) => { 処理 }


3.比較


 例として、2つの数値の和を返すメソッドをそれぞれの方法で定義してみましょう。

<匿名メソッドの場合>

Func<int, int, int> add = delegate(int x, int y) { return x + y; };


<ラムダ式の場合>

Func<int, int, int> add = (x, y) => { return x + y; };

 どちらも同じ機能を持つメソッドを定義していますが、ラムダ式の方が簡潔に書くことができます。



まとめ


 ・ラムダ式はデリゲートを使ったコードを短く書くために利用されます。
 ・デリゲートに渡す匿名メソッドをラムダ式で簡潔に記述できます。

 デリゲートとラムダ式は、C# においてメソッドを扱うための重要な概念です。
デリゲートは、メソッドへの参照を保持するオブジェクトであり、ラムダ式は、簡潔に匿名関数を定義する構文です。

 デリゲートとラムダ式を組み合わせることで、コードがシンプルで読みやすくなり、柔軟なプログラミングが可能になります。


 
 以上になります。

 次は デリゲートとラムダ式の活用事例 です。