こんにちは。明月です。
この投稿はC#のデリゲート(delegate)を使う方法に関する説明です。
C#のデリゲートは代理子のいう意味でC++の関数ポインタと似ている概念を持っているキーワードです。つまり、関数ポインタとは関数式(function)をインスタンスのポインタみたいに認識して変数に値を格納するかパラメータに渡して実行する代理に実行する役をします。
using System;
namespace Example
{
class Program
{
// デリゲート宣言
delegate void PrintDelegate(String str);
// 出力関数
public void Print(String str)
{
// コンソール出力
Console.WriteLine(str);
}
public Program()
{
// デリゲートにメソッドを格納
// デリゲートの変換タイプ、パラメータが一致するべき。
PrintDelegate pd = new PrintDelegate(Print);
// デリゲート実行
pd("Hello World");
}
static void Main(string[] args)
{
// インスタンスを生成してコンストラクタを実行
new Program();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例でPrint関数をデリゲートで使ってポインタでインスタンスのポインタを変換してpdの変数をインスタンス値みたいに使えます。
実行はデリゲートの変数でただ関数を呼び出すみたいにパラメータ値を入れれば実行されて、コンソール出力することを確認できます。
上の式はデリゲートを説明するために凄くシンプルに作成したことで実際は変数の値みたいに使ういい点があります。
using System;
using System.Collections.Generic;
namespace Example
{
// インタフェース
interface INode
{
// 関数宣言
void Print(String str);
}
// デリゲートがあるクラス
class Example : INode
{
// 変換値がvoidで、Stringパラメータが一つあるデリゲート
// デリゲートを外部から使うためにアクセス修飾子をpublicで設定するべき。
public delegate void PrintDelegate(String str);
// 関数ポインタを格納するためのリスト
private List<PrintDelegate> list = new List<PrintDelegate>();
// 関数追加
public void AddDelegate(PrintDelegate func)
{
list.Add(func);
}
// Print関数を実行すればリストに格納された関数を実行する。
public void Print(String str)
{
// 繰り返しでリストに格納する関数を取得。
foreach (var item in list)
{
// 関数を実行
item(str);
}
}
}
// Node1クラス
class Node1 : INode
{
// Print関数
public void Print(String str)
{
// コンソール出力
Console.WriteLine("Node1 print - " + str);
}
}
// Node2クラス
class Node2 : INode
{
// Print関数
public void Print(String str)
{
// コンソール出力
Console.WriteLine("Node2 print - " + str);
}
}
class Program
{
// 実行関数
static void Main(string[] args)
{
// デリゲートがあるクラスのインスタンスを生成
Example example = new Example();
// Node1クラスのインスタンスを生成
INode node1 = new Node1();
// Node2クラスのインスタンスを生成
INode node2 = new Node2();
// デリゲートがあるクラスにNode1クラスのPrint関数を登録
example.AddDelegate(node1.Print);
// デリゲートがあるクラスにNode2クラスのPrint関数を登録
example.AddDelegate(node2.Print);
// デリゲートがあるクラスのPrint関数にTest値を格納して実行
example.Print("Test");
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例をみればExample클래스とNode1、Node2クラスをINodeインタフェースを継承しました。
上の形式はデザインパターンの中で合成パターンです。ExampleクラスにNode1クラスのPrint関数とNode2クラスのPrint関数を入れてExampleクラスのPrint関数を実行すれば同時に実行されるパターンです。
上の例は私がListにデリゲートを格納して関数ポインタを管理するようにしました。
でも、デリゲートは関数を管理するリスト機能もあります。+=と-=の対入演算子を通って追加、削除をできます。
using System;
using System.Collections.Generic;
namespace Example
{
// インタフェース
interface INode
{
// 関数宣言
void Print(String str);
}
// デリゲートがあるクラス
class Example : INode
{
// 変換値がvoidで、Stringパラメータが一つあるデリゲート
// デリゲートを外部から使うためにアクセス修飾子をpublicで設定するべき。
public delegate void PrintDelegate(String str);
// 関数ポインタを格納するためのリスト
private PrintDelegate list;
// 関数追加
public void AddDelegate(PrintDelegate func)
{
list += func;
}
// 関数削除
public void RemoveDelegate(PrintDelegate func)
{
list -= func;
}
// Print関数を実行すればリストに格納された関数を実行する。
public void Print(String str)
{
list(str);
}
}
// Node1クラス
class Node1 : INode
{
// Print関数
public void Print(String str)
{
// コンソール出力
Console.WriteLine("Node1 print - " + str);
}
}
// Node2クラス
class Node2 : INode
{
// Print関数
public void Print(String str)
{
// コンソール出力
Console.WriteLine("Node2 print - " + str);
}
}
class Program
{
// 実行関数
static void Main(string[] args)
{
// デリゲートがあるクラスのインスタンスを生成
Example example = new Example();
// Node1クラスのインスタンスを生成
INode node1 = new Node1();
// Node2クラスのインスタンスを生成
INode node2 = new Node2();
// デリゲートがあるクラスにNode1クラスのPrint関数を登録
example.AddDelegate(node1.Print);
// デリゲートがあるクラスにNode2クラスのPrint関数を登録
example.AddDelegate(node2.Print);
// デリゲートがあるクラスのPrint関数にTest値を格納して実行
example.Print("Test");
// デリゲートでnode1.Print関数を削除
example.RemoveDelegate(node1.Print);
// デリゲートがあるクラスのPrint関数にTest値を格納して実行
example.Print("Hello world");
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例には二つ目のListクラスの変わりにデリゲートで関数式を追加、削除することができます。
最近にはC#コードでラムダ式(lambda)をよく見えますが、このラムダ式がデリゲート基盤で生成して使います。
using System;
using System.Collections.Generic;
namespace Example
{
// デリゲートがあるクラス
class Example
{
// 変換値がvoidで、Stringパラメータが一つあるデリゲート
// デリゲートを外部から使うためにアクセス修飾子をpublicで設定するべき。
public delegate void PrintDelegate(String str);
// 関数ポインタを格納するためのリスト
private PrintDelegate list;
// 関数追加
public void AddDelegate(PrintDelegate func)
{
list += func;
}
// 関数削除
public void RemoveDelegate(PrintDelegate func)
{
list -= func;
}
// Print関数を実行すればリストに格納された関数を実行する。
public void Print(String str)
{
list(str);
}
}
class Program
{
// 実行関数
static void Main(string[] args)
{
// デリゲートがあるクラスのインスタンスを生成
Example example = new Example();
// ラムダ式で関数を追加
example.AddDelegate((str) =>
{
Console.WriteLine("Lambda - " + str);
});
// デリゲートがあるクラスのPrint関数にTest値を格納して実行
example.Print("Test");
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
ラムダ式は匿名関数の意味で関数で名前がない関数という意味です。このラムダ式は関数名が存在しないので関数ポインタだけ存在します。
つまり、ラムダ式を使うためにはこのデリゲートで関数のポインタを持つべきだと意味です。
ラムダ式はラムダ式を説明する時にもっと詳細に説明します。
ここまでC#のデリゲート(delegate)を使う方法に関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [C#] 30. Linq関数式を使う方法2019/07/17 23:06:42
- [C#] 29. Linqクエリ式を使い方2019/07/17 20:57:00
- [C#] 28. リスト(List)とディクショナリ(Dictionary)、そしてLinq式を使い方2019/07/16 22:40:03
- [C#] 27. varキーワードとdynamicキーワード2019/07/16 20:41:27
- [C#] 26. 例外処理(try ~ catch)する方法2019/07/16 00:59:34
- [C#] 25. イベント(event)キーワードを使い方2019/07/16 00:48:03
- [C#] 24. ラムダ式(匿名関数)とAction、Func関数を使い方、そしてクロージャ(Closure)2019/07/16 00:36:19
- [C#] 23. デリゲート(delegate)2019/07/15 02:25:26
- [C#] 22. インデクサー(indexer)を使う方法2019/07/13 01:06:04
- [C#] 21. C#のプロパティ(Property)2019/07/13 00:56:20
- [C#] 20. オブジェクト指向プログラミング(OOP)の4つの原則(カプセル化、抽象化、継承化、多相化(ポリモーフィズム))2019/07/12 00:17:35
- [C#] 19. 列挙型(enum)を使う方法2019/07/11 23:13:25
- [C#] 18. 構造体(Struct)、そして値型を参照するタイプ(Reference of value type)と参照型を参照するタイプ(Reference of reference type)2019/07/10 23:57:25
- [C#] 17. thisとbaseのキーワード2019/07/10 23:43:56
- [C#] 16. 継承禁止のキーワードのsealed2019/07/10 00:19:18
- check2024/04/10 19:03:53
- [Java] 64.Spring bootとReactを連結する方法(Buildする方法)2022/03/25 21:02:18
- [Javascript] Node.jsをインストールしてReactを使う方法2022/03/23 18:01:34
- [Java] 63. Spring bootでcronスケジューラとComponentアノテーション2022/03/16 18:57:30
- [Java] 62. Spring bootでWeb-Filterを設定する方法(Spring Security)2022/03/15 22:16:37
- [Java] JWT(Json Web Token)を発行、確認する方法2022/03/14 19:12:58
- [Java] 61. Spring bootでRedisデータベースを利用してセッションクラスタリング設定する方法2022/03/01 18:20:52
- [Java] 60. Spring bootでApacheの連結とロードバランシングを設定する方法2022/02/28 18:45:48
- [Java] 59. Spring bootのJPAでEntityManagerを使い方2022/02/25 18:27:48
- [Java] 58. EclipseでSpring bootのJPAを設定する方法2022/02/23 18:11:10
- [Java] 57. EclipseでSpring bootを設定する方法2022/02/22 19:04:49
- [Python] Redisデータベースに接続して使い方2022/02/21 18:23:49
- [Java] Redisデータベースを接続して使い方(Jedisライブラリ)2022/02/16 18:13:17
- [C#] Redisのデータベースを接続して使い方2022/02/15 18:46:09
- [CentOS] Redisデータベースをインストールする方法とコマンドを使い方2022/02/14 18:33:07