C#において、delegateキーワードを使った匿名関数は、コードの記述を簡潔にする重要な機能です。前回のエントリではdelegateの基本的な使い方について解説しましたが、今回は匿名関数とLambda式についてより深く掘り下げていきます。
上記のコードでは、2つのMessagePrinterオブジェクトを作成しています。従来대로のdelegate使用方法では、DisplayMessageメソッドを事前に定義しておく必要がありましたが、匿名関数を使用することでその場限りの処理を直接記述できます。
上記の例で分かるように、delegateキーワードを記述する必要がなくなり、代わりに=>演算子を使用して簡潔に記述できます。パラメータの型推論が可能な場合は、型を省略して記述することも可能です。
匿名関数の基本
匿名関数とは、その名が示す通り、名前を持たない関数のことです。従来の方法では、委托を宣言してインスタンス化し、定義済みメソッドを関連付けていましたが、頻繁に利用しないメソッドの場合、これは面倒な作業でした。匿名関数を使用すれば、その場で直接メソッドを定義できます。匿名関数の記法
委托名 変数名 = delegate(パラメータリスト)
{
// 処理内容
};
- パラメータリスト: 委托で宣言されたパラメータと一致する必要があります。パラメータがない場合は空の括弧()を使用します。
- 戻り値: 委托の戻り値タイプと一致させる必要があります。
実装例
具体的な例として、単純な文字列出力を提供するクラスを使用して説明します。using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnonymousMethodDemo
{
// void戻り値でstring型パラメータを1つ持つメソッドを参照する委托を定義
public delegate void MessageDelegate(string message);
public class MessagePrinter
{
public string PrinterName { get; set; }
public MessageDelegate messageHandler;
public MessagePrinter(string name)
{
PrinterName = name;
}
public void Print()
{
if (messageHandler != null)
{
messageHandler($" Printer: {PrinterName}");
}
}
}
}using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnonymousMethodDemo
{
class Program
{
static void Main(string[] args)
{
// 従来delegate声明したメソッドを使用する場合
MessagePrinter hpPrinter = new MessagePrinter("HP-LaserJet");
hpPrinter.messageHandler += new MessageDelegate(DisplayMessage);
hpPrinter.Print();
Console.WriteLine("--------------------------------------");
// 匿名関数を使用した例
MessagePrinter canonPrinter = new MessagePrinter("Canon-ix6800");
// 匿名関数を変数に代入して後から使用
MessageDelegate canonMessage = delegate (string msg)
{
Console.WriteLine($"Canon printing{msg}");
};
// 匿名関数を直接委托に割り当て
canonPrinter.messageHandler = delegate (string msg)
{
Console.WriteLine($"Canon device{msg}");
};
// 変数に代入した匿名関数を追加
canonPrinter.messageHandler += canonMessage;
canonPrinter.Print();
Console.ReadLine();
}
static void DisplayMessage(string message)
{
Console.WriteLine($"HP printing{message}");
}
}
}匿名関数の利点
- コードの可読性
従来の方法では、委托インスタンスの生成と実際のメソッド定義が別の場所に記述されるため、コードレビュー時に何度もページをスクロールする必要があります。匿名関数を使用すれば、调用箇所と実装が近接しているため、論理フローを追いやすくなります。 - スコープの限定
通常のメソッドはクラスレベルで定義されますが、匿名関数は调用元のメソッド内に記述できるため、スコープを限定できます。一回限りの処理や特定の場所だけで使用するロジックを場合に、クラス全体を汚染せずに済みます。
Lambda式への進化
匿名関数は便利ですが、より簡潔に記述できないかという要望がありました、そこで登場するのがLambda式です。Lambda式は匿名関数のさらに短い記法です。Lambda式の記法
(パラメータリスト) => 式またはブロック
「=>」はLambda演算子」と呼ばれ、左側に入力パラメータ、右側に式の本体を記述します。
同じ例をLambda式で書き直すと以下のようになります:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LambdaDemo
{
class Program
{
static void Main(string[] args)
{
MessagePrinter hpPrinter = new MessagePrinter("HP-LaserJet");
hpPrinter.messageHandler += new MessageDelegate(DisplayMessage);
hpPrinter.Print();
Console.WriteLine("--------------------------------------");
MessagePrinter canonPrinter = new MessagePrinter("Canon-ix6800");
// Lambda式を使用した单一パラメータの例
canonPrinter.messageHandler = (string msg) =>
{
Console.WriteLine($"Canon device{msg}");
};
// 複数のハンドラをLambda式で追加
canonPrinter.messageHandler += (string msg) =>
{
Console.WriteLine($"Canon printing{msg}");
};
canonPrinter.Print();
Console.ReadLine();
}
static void DisplayMessage(string message)
{
Console.WriteLine($"HP printing{message}");
}
}
}