0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C#】delegate、Action、Func、匿名メソッド、ラムダ式のざっくりとした使い方

Last updated at Posted at 2024-10-05

記事タイトルの項目について理解が甘かったため、勉強してまとめました。

動作確認環境

C# 7.3
.Net Framework 4.7.2

delegate

関数への参照を表す型のこと。
デリゲート型の変数を使用することで、参照している関数を呼び出すことができる。

// 参照したい関数と同じ戻り値・引数のデリゲートを定義
private delegate void DelegateType(int i);

static void Main()
{
    // デリゲートのインスタンスを作成
    DelegateType func = new DelegateType(DisplayNum);

    // DisplayNum(1)を呼び出したことになる
    func(1);
}

// 引数の数値をコンソールに表示
private static void DisplayNum(int i)
{
    Console.WriteLine($"引数の値は {i} です");
}

インスタンス作成の行は、以下のような書き方も可能です。
こちらの方が直感的に理解できるのではないでしょうか。

// 参照したい関数と同じ戻り値・引数のデリゲートを定義
private delegate void DelegateType(int i);

static void Main()
{
    // デリゲートのインスタンスを作成
    DelegateType func = DisplayNum;

    // DisplayNum(1)を呼び出したことになる
    func(1);
}

// 引数の数値をコンソールに表示
private static void DisplayNum(int i)
{
    Console.WriteLine($"引数の値は {i} です");
}

「int num = 1;」とした場合にnumを1として扱えるのと同様、「DelegateType func = DisplayNum;」とすればfuncをDisplayNum関数として扱えます。

以下は戻り値を返す場合の例。

private delegate int DelegateType2(string str);

 static void Main()
 {
     DelegateType2 func = GetStrLen;

     // GetStrLen("abc")を呼び出したことになる
     int len = func("abc");
     Console.WriteLine($"文字数は {len} です");
 }

 // 引数の文字列の文字数を返却する
 private static int GetStrLen(string str)
 {
     return str.Length;
 }

一つのデリゲート型の変数で複数の関数を参照することもできますが、この記事では割愛します。

Action

簡略化したdelegate。
引数は指定できるが、戻り値は指定できない。

以下はdelegateの項のソースと同じ結果になります。

static void Main()
{
    // 「Action<参照する関数の引数1, 引数2, ...>」のように定義する
    Action<int> func = DisplayNum;

    // DisplayNum(1)を呼び出したことになる
    func(1);
}

// 引数の数値をコンソールに表示
private static void DisplayNum(int i)
{
    Console.WriteLine($"引数の値は {i} です");
}

ちなみにActionは以下のように定義されています。

public delegate void Action<in T>(T obj);

戻り値無しのデリゲートを、.Net Framework側が「Action」という名前で事前に用意してくれているということですね。
そのためdelegateの項の「DelegateType」のように、わざわざ自前で実装する必要がありません。

なお、Actionの引数は以下の通り0~16個の範囲で指定可能です。

public delegate void Action();
public delegate void Action<in T>(T obj);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);

public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

Func

簡略化したdelegate。
Actionと違い、戻り値も指定可能。

static void Main()
{
    // 「Func<参照する関数の引数1, 引数2, ... , 参照する関数の戻り値>」のように定義する
    Func<string, int> func = GetStrLen;

    // GetStrLen("abc")を呼び出したことになる
    int len = func("abc");
    Console.WriteLine($"文字数は {len} です");
}

// 引数の文字列の文字数を返却する
private static int GetStrLen(string str)
{
    return str.Length;
}

こちらも定義を見てみましょう。
Actionと違い、戻り値としてTResultが追加されていますね。

public delegate TResult Func<in T, out TResult>(T arg);

FuncもActionと同様、引数を0~16個の範囲で指定可能です。

public delegate TResult Func<out TResult>();
public delegate TResult Func<in T, out TResult>(T arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);

public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);

匿名メソッド

参照するタイミングで定義する関数。
一箇所でしか参照しないような関数や、簡単な関数の場合、わざわざ事前に定義せずこの方法を使用したりする。

以下はAction、Funcの項のソースと同じ結果になります。
参照する関数の定義を、インスタンス作成行の右辺に移動しています。

static void Main()
{
    Action<int> func = delegate (int i) { Console.WriteLine($"引数の値は {i} です"); };
    
    func(1);
}
static void Main()
{
    Func<string, int> func = delegate (string str) { return str.Length; };

    int len = func("abc");
    Console.WriteLine($"文字数は {len} です");
}

匿名メソッドは「delegate (関数の引数) {関数の処理}」のような記述をします。
関数名が無い以外は通常の関数と同様、つまり「名前のない関数」=「匿名メソッド」です。

ラムダ式

簡略化した匿名メソッド。

こちらもAction、Funcの項のソースと同じ結果になります。匿名メソッドよりも更に関数定義が簡単になっています。

static void Main()
{
    Action<int> func = (int i) => { Console.WriteLine($"引数の値は {i} です"); };
    
    func(1);
}
static void Main()
{
    Func<string, int> func = (string str) => { return str.Length; };

    int len = func("abc");
    Console.WriteLine($"文字数は {len} です");
}

更に関数定義を省略することができます。
ネット上ではこちらの書き方をよく見かけます。

static void Main()
{
    Action<int> func = i => Console.WriteLine($"引数の値は {i} です");
    
    func(1);
}
static void Main()
{
    Func<string, int> func = str => str.Length;

    int len = func("abc");
    Console.WriteLine($"文字数は {len} です");
}

ラムダ式の使用例。

static void Main()
{
    // 非同期処理
    Task.Run(() => { Console.WriteLine("非同期処理です"); });
    

    // LINQなど
    var lst = new List<int> { 9, 99, 999 };
    
    // 10以上の値の要素のみ取り出して、新しいリストを作成
    // 要素ごとにWhereの引数の関数を実施し、trueを返すならばその要素を取り出す
    var newLst = lst.Where((int num) => { return num >= 10; }).ToList();
    //var newLst = lst.Where(num => num >= 10).ToList();    // 省略形
    
    // 新しいリストの各要素の値をコンソールに表示
    // 要素ごとにForEach引数の関数を実施する
    newLst.ForEach((int num) => { Console.WriteLine($"要素の値は {num} です"); });
    //newLst.ForEach(num => Console.WriteLine($"要素の値は {num} です"));    // 省略形
}

まとめ

図.png

参考URL

【C#】delegate, Action, Funcについて 多分一番易しい解説
Action<T> Delegate (System) | Microsoft Learn
Func<T,TResult> Delegate (System) | Microsoft Learn
ラムダ式 - ラムダ式と匿名関数 - C# reference | Microsoft Learn

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?