C#　超入門 丁寧に解説　デリゲート

# はじめに
現場でC#を使って開発をしています。デリゲートの使い方について一から学んだので備忘録として書いています。間違いがあればコメントお願いします。

# デリゲートとは？
メソッドを参照するための型のこと。他のメソッドへの引数としてメソッドを渡すために使用される。
公式資料

https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/delegates/


# 実際に使ってみた
```C#:
delegate bool LenCheck(string value); //①デリゲート宣言

private bool Shiki1(string value) //②メソッド実装
{
    return value.Length == 3;
}

 private string[] GetValue3(string[] values, LenCheck lenCheck) //③デリゲートを使用するメソッド
 {
     var result = new List<string>();
     foreach (var val in values)
     {
         if (lenCheck(val))
         {
             result.Add(val);
         };
     }

     return result.ToArray();
 }
 
 private void button1_Click(object sender, EventArgs e) //④メソッドの実行
 {
     var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
     var result = GetValue3(values, Shiki1);

     Console.WriteLine(string.Join(",", result));
 }

引用元:https://anderson02.com/cs/lambda/lambda07/
```


# コードの解説
### ①デリゲート宣言
```C#
delegate   bool    LenCheck(string value);
delegate   戻り値   名前（型名）   引数
```
LenCheckという名前のデリゲート型を宣言。string型の引数を受け取り、bool型の戻り値を返すメソッドであることを示している。

### ②メソッド実装
```C#
private bool Shiki1(string value) 
{
    return value.Length == 3;
}
```
①で宣言したデリゲートと引数、戻り値を合わせる。なのでstring型の引数を受け取り、bool型を戻り値のメソッドを定義。

### ③デリゲートを使用するメソッド
```C#
private string[] GetValue3(string[] values, LenCheck lenCheck) 
 {
     var result = new List<string>();
     foreach (var val in values)
     {
         if (lenCheck(val))
         {
             result.Add(val);
         };
     }

     return result.ToArray();
 }
```
GetValue3メソッドがLenCheckデリゲートを引数として受け取る。つまり引数としてメソッドを渡されている。
この例では、引数としてlenCheck＝Shiki1メソッドを受け取っている。
また、foreachで各要素に対してlenCheck(Shiki1）が呼び出し、value.Length == 3の場合はtrueを戻り値として返す。valがstring型以外になるとエラーとなる。

④メソッド実行
button1_Clickメソッドが実行されると、「CCC」がコンソール上に表示されます。


# 定義済みデリゲート
.NETの標準ライブラリに存在するデリゲート型のこと。
自分でデリゲートを定義する必要がなくなり、なにかと便利。
Predicate,Func,Actionがある。

## Predicate<T>型
１つ引数を受け取り、戻り値がbool型を返す

①引数としてPredicate　pridicateをデリゲート宣言がいらない。
②GetValue8のpredicateと合わせるためstring型引数を受け取ることは宣言
value.Length == 3;で真が返されると、result.Add(val);で値が追加される。


```C#
private string[] GetValue8(string[] values, Predicate<string> predicate)//①Predicate型を引数として受け取る
{
    var result = new List<string>();
    foreach (var val in values)
    {
        if (predicate(val))
        {
            result.Add(val);
        };
    }

    return result.ToArray();
}
private void button8_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };
    var result = GetValue8(
        values,
        delegate (string value)//②GetValue8のpredicateと合わせる
        {
            return value.Length == 3;
        }
        );
    Console.WriteLine(string.Join(",", result));
}
```




## Func型
戻り値のあるメソッドが定義されている、引数は０～１６個まで可。
②引き合数string value, int lenを受け取り、value.Length >= lenの結果を返す。
value.Length >= lenで真だと、result.Add(val);で値が追加される。
```C#:
private string[] GetValue10(string[] values, int len, 
    Func<string, int, bool> lenCheck) //①引数2つ(string,int)を受け取り、戻り値boolを返す
{
    var result = new List<string>();
    foreach (var val in values)
    {
        if (lenCheck(val, len))
        {
            result.Add(val);
        };
    }

    return result.ToArray();
}

private void button10_Click(object sender, EventArgs e)
{
    var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" };

    var tokumei = GetValue10(values, 2,
                            delegate (string value, int len)//②①のFunc<string, int, bool> lenCheckと合わせる
                            {
                                return value.Length >= len;
                            });
    Console.WriteLine(string.Join(",", tokumei));
}
```
## Action型
戻り値のないメソッドが定義されている、引数は０～１６個まで可。
②引数int型を受け取り、戻り値なしのメソッドが実行される。この例では、Console.WriteLine(value);が1秒ごとに5回実行されるため、コンソール上に20,40,60,80,100が表示される。

```C#


    private List<string> GetData(Action<int> progressAction) //①引数intを受け取り、戻り値はなし
{
    var result = new List<string>();
    for (int i = 1; i <= 5; i++)
    {
        result.Add(DateTime.Now.ToString("yyyy/dd HH:mm:ss.ff"));
        System.Threading.Thread.Sleep(1000);
        progressAction(i * 20); //②①のAcrion<int>progressActionと合わせる
    }
    return result;
}

private void DoConsole(int value) 
{
    Console.WriteLine(value);
}

private void button12_Click(object sender, EventArgs e)
{
    GetData(DoConsole);
}

```


参考文献
https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/delegates/
https://anderson02.com/cs/lambda/lambda06/
https://learn.microsoft.com/ja-jp/dotnet/standard/delegates-lambdas
https://learn.microsoft.com/en-us/dotnet/api/system.predicate-1?view=net-8.0
https://learn.microsoft.com/en-us/dotnet/api/system.func-1?view=net-8.0
https://learn.microsoft.com/en-us/dotnet/api/system.action-1?view=net-8.0