メソッドの参照。型安全な関数ポインタ。
成果物
情報源
- https://docs.microsoft.com/ja-jp/dotnet/csharp/tour-of-csharp/delegates
- https://ufcpp.net/study/csharp/sp_delegate.html
デリゲート型の定義と宣言
class Program { delegate int GetValue(); static void Main() { GetValue getValue; getValue = Get100; } static int Get100() => 100; }
インスタンスメソッドに対しても使える。
class Main { delegate int GetValue(); public void Run() { GetValue getValue; getValue = Get100; } int Get100() => 100; }
マルチキャストデリゲート
複数のメソッドをセットできる。呼び出せばすべてのメソッドが実行される。
class Main { delegate int GetValue(); public void Run() { GetValue getValue; getValue = Get100; getValue += Get0_99; Console.WriteLine($"{getValue()}"); } int Get100() { Console.WriteLine("called Get100."); return 100; } int Get0_99() { Console.WriteLine("called Get0_99."); return new Random().Next(100); } }
ただし、戻り値は最後のGet0_99
メソッドの値だけだった。
エラー
デリゲートの型宣言を関数内でやるとエラー
error CS1514: { expected error CS1002: ; expected
クラスのメンバ変数として宣言してやると成功する。
class Main { public void Run() { delegate int GetValue(); // error GetValue getValue; getValue = Get100; } int Get100() => 100; }
おそらくdelegate
は型の一種。型の定義はメソッド内では不可。namespace
かclass
内で定義するものなのだろう。たぶん。
用途
述語
class Main { delegate bool Predicate(int i); public void Run() { Predicate p; int[] a = {1,2,3,4,5}; p = IsEven; int[] evens = Select(a, p); Show(evens); p = IsOdd; int[] odds = Select(a, p); Show(odds); } int[] Select(int[] a, Predicate p) { List<int> list = new List<int>(); foreach (int v in a) { if (p(v)) { list.Add(v); } } return list.ToArray(); } bool IsEven(int i) => (0 == (i % 2)); bool IsOdd(int i) => (1 == (i % 2)); void Show(int[] a) { foreach (int i in a) { Console.WriteLine($"{i}"); } } }
Select
は、配列a
の要素が述語p
である要素のみの配列を返す。
述語は変数にできる。この場合は以下2通り。
IsEven
: 偶数であるIsOdd
: 奇数である
好きな述語メソッドを定義できる。使うときは自由に選択できる。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13 ※
- bash 4.4.12(1)-release ※
- SQLite 3.29.0 ※
- C# dotnet 3.0.100 ※
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux