デリゲートを引数に与える関数でラムダ式を利用する - C#

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を愛用
最終更新日: 2024-01-07
作成日: 2016-07-15
iPentec all rights reserverd.