はじめに
現場で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/
コードの解説
①デリゲート宣言
delegate bool LenCheck(string value);
delegate 戻り値 名前(型名) 引数
LenCheckという名前のデリゲート型を宣言。string型の引数を受け取り、bool型の戻り値を返すメソッドであることを示している。
②メソッド実装
private bool Shiki1(string value)
{
return value.Length == 3;
}
①で宣言したデリゲートと引数、戻り値を合わせる。なのでstring型の引数を受け取り、bool型を戻り値のメソッドを定義。
③デリゲートを使用するメソッド
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型
1つ引数を受け取り、戻り値がbool型を返す
①引数としてPredicate pridicateをデリゲート宣言がいらない。
②GetValue8のpredicateと合わせるためstring型引数を受け取ることは宣言
value.Length == 3;で真が返されると、result.Add(val);で値が追加される。
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型
戻り値のあるメソッドが定義されている、引数は0~16個まで可。
②引き合数string value, int lenを受け取り、value.Length >= lenの結果を返す。
value.Length >= lenで真だと、result.Add(val);で値が追加される。
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型
戻り値のないメソッドが定義されている、引数は0~16個まで可。
②引数int型を受け取り、戻り値なしのメソッドが実行される。この例では、Console.WriteLine(value);が1秒ごとに5回実行されるため、コンソール上に20,40,60,80,100が表示される。
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