デリゲートを引数に与える関数でラムダ式を利用する
C#のラムダ式をデリゲートを引数に取る関数で利用する例を紹介します。
プログラム
UI
コード1
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace InputDelegate
{
public partial class FormMain : Form
{
delegate int SimpleFunc(int x);
public FormMain()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int result = Proc(operation);
textBox1.Text = "Result:" + result.ToString();
}
private int Proc(SimpleFunc func)
{
return func(12);
}
private int operation(int input) {
return input * 2;
}
}
}
解説
Procメソッドがデリゲートを引数に持つメソッドです。button1_clickメソッドで、Procメソッドを呼び出しています。Procメソッドの引数には、operationメソッドを与えています。
Procメソッド内で引数のfuncに引数12を与えて呼び出すことで、引数に与えたoperationメソッドが実行され、12の2倍の24がProcメソッドの戻り値となり、テキストボックスに値が表示されます。
なお、Procメソッドの呼び出しは、C#1.0の書式では以下の記述になります。
SimpleFunc sf = new SimpleFunc(operation);
int result = Proc(sf);
コード2
上記のコード1を下記に変更します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace InputDelegate
{
public partial class FormMain : Form
{
delegate int SimpleFunc(int x);
public FormMain()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int result = Proc(delegate(int input){ return input * 2; });
textBox1.Text = "Result:" + result.ToString();
}
private int Proc(SimpleFunc func)
{
return func(12);
}
}
}
解説
コード1ではoperationメソッドを用意しましたが、1度しか使わないメソッドのため、メソッドとして定義すると冗長になります。そこで、メソッドの実体を持たない匿名メソッドを利用します。匿名メソッドの書式は
delegate (引数の型 引数名, ..... ) { /*匿名メソッドの実装*/ }
となります。
先のコードのoperationメソッドの実装を匿名メソッドに置き換え
delegate(int input){ return input * 2; }
と記述し、これをProcメソッドの引数に与えます。
動作は先のコードと全く同じ動作になります。
コード3
上記のコードを下記に変更します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace InputDelegate
{
public partial class FormMain : Form
{
delegate int SimpleFunc(int x);
public FormMain()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int result = Proc((input) => input * 2);
textBox1.Text = "Result:" + result.ToString();
}
private int Proc(SimpleFunc func)
{
return func(12);
}
}
}
解説
コード2では匿名メソッドを利用しましたが、演算結果のみを処理する場合、中括弧や、return文などが冗長のため、メソッドで利用するブロック的な記述より、もっとシンプルに記述したいといったニーズがあります。ラムダ式を用いると、ブロック的な記述を演算式のような記述で表現できます。
delegate(int input){ return input * 2; }
は
(input) => input * 2
と置き換えられます。"=>"の右辺は1文で表現し、(return文なしで)演算結果が戻り値となります。
実行結果
上記のコード3つとも同じ実行結果になります。
プロジェクトを実行します。下図のウィンドウが表示されます。
[button1]をクリックします。テキストボックスに結果「24」が表示されます。
補足:ラムダの書式
ラムダ式の書式は以下になります。
パラメーターが無い場合 (式形式のラムダ)
() => 処理
パラメーターが無い場合の括弧は省略できません。
引数が1つの場合 (式形式のラムダ)
(引数名) => 処理
(引数の型 引数名) => 処理
引数が一つの場合のみ、括弧を省略できます。
引数名 => 処理
引数の型 引数名 => 処理
引数が複数の場合 (式形式のラムダ)
(引数名1, 引数名2, ....) => 処理
(引数型1 引数名1, 引数型2 引数名2, ....) => 処理
複数文を記述する (ステートメント形式のラムダ)
なお、ラムダ式であっても複数文を処理する記述も可能です。複数文を処理する場合は中括弧のブロックを記述します。
引数が無い場合
() =>{
処理1;
処理2;
処理3;
return (変数または値);
}
引数が1つの場合
(引数名) =>{
処理1;
処理2;
処理3;
return (変数または値);
}
(引数型 引数名) =>{
処理1;
処理2;
処理3;
return (変数または値);
}
引数が複数の場合
(引数名1, 引数名2, ....) =>{
処理1;
処理2;
処理3;
return (変数または値);
}
(引数型1 引数名1, 引数型2 引数名2, ....) =>{
処理1;
処理2;
処理3;
return (変数または値);
}
複数文を記述した場合は、return文が必要です。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用