(1) C#のデリゲートが分からない・・を解決!初心者向けになるべく分かり易く説明してみた
(1-1) デリゲートとは?「関数へのポインタ」だけでは説明しきれない・・
(1-2) デリゲートの用途
(1-3) コールバック関数の実装手順(例)
(1-4) コールバック関数サンプルプログラム
(1) C#のデリゲートが分からない・・を解決!初心者向けになるべく分かり易く説明してみた
(1-1) デリゲートとは?「関数へのポインタ」だけでは説明しきれない・・
良くある説明では「関数へのポインタ」と説明されていたりします。この言葉を素直に解釈するならデリゲートは「ポインタ」なので、ある関数の「アドレス」の情報を保持しているものになります。

これを実際のプログラムに起こすと、例えば次のような記述になります(※デリゲートの本来の力を発揮していない例です)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelegateTest
{
class Program2
{
//②ある関数「LoopPointer」へのポインタとなるデリゲートの作成
public delegate void LoopPrintPointer();
static void Main(string[] args)
{
//③ポインタに関数のアドレスを代入
LoopPrintPointer lpp = new LoopPrintPointer(LoopPrint);
lpp.Invoke();
}
//①ある関数「LoopPrint」を定義
static void LoopPrint()
{
//何かしらの処理
Console.WriteLine("### Method invoked");
}
}
}
(図112)

(1-2) デリゲートの用途
デリゲートは主に「イベント」や「コールバック関数」の実装に使われます。
「イベント」はユーザーのアクション(例:ボタン押下やマウスクリック等)。
「コールバック関数」というのは「ある関数の引数」として渡される別の関数の事を「コールバック関数」と呼んでいます。コールバック関数は呼び出し先の処理の中で実行(コールバック)され、処理の完結に寄与します。渡した先で再度呼ばれる挙動から「コールバック関数」と名が付いています。
(1-3) コールバック関数の実装手順(例)
では、実際にコールバック関数をデリゲートを使って作成する例を見てみます。
まずは次のようなプログラムがあるとします。ポイントはクラスが2つ「Program」と「SampleClass」があり、最終的にはデリゲートを使って、Programクラスの中でSampleClassの処理状況をリアルタイムに取得するような動きを、コールバック関数を使って実現していきます。
(Before:初期状態⇒※これからdelegate関連の記述を追記します)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelegateTest
{
class Program
{
static void Main(string[] args)
{
//SampleClassをインスタンス化
SampleClass sc = new SampleClass();
//メソッド実行
sc.LoopPrint();
}
}
public class SampleClass
{
//ある関数
public void LoopPrint()
{
//何かしらの処理
for (int i = 0; i < 5000; i++)
{
//何かしらの処理
}
}
}
}
(図113)

(1-4) コールバック関数サンプルプログラム
サンプルプログラムをご紹介する前に、追記するコードを理解しやすいよう、デリゲートの概念についてお伝えしたいと思います。
冒頭にもあったとおり、デリゲートはclassとclassを繋ぐ「使節」のような派遣とイメージする事が出来ると思います。
その例えで行くと、delegate型の変数定義(右上)は「使節の受け入れ枠」のようなイメージでしょうか。他クラスからの関数を受け入れる定義として、
delegate型の変数を定義しています。
そしてコールバック関数(右下)は「使節が来訪した際にお願いするタスク」のようなイメージでしょうか。引数にdelegate型(Callback callback)を受取り、そのデリゲート(ポインタ)が指す関数を実行します。
デリゲート(関数へのポインタ)に引き渡す関数自体(左中央)は「使節」のイメージでしょうか。実際に派遣される使節(メソッド)の定義です。
(図114)デリゲートの概念図

これらを踏まえて、上記のBeforeのプログラムにデリゲートに関する記述を追加したものが下記になります。
(After:デリゲート実装後)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelegateTest
{
class Program
{
static void Main(string[] args)
{
SampleClass sc = new SampleClass();
//⑤関数実行時の引数に④の関数を与える
sc.LoopPrint(Callback);
}
//④コールバック時に実行する関数の処理を定義します
// ※例えるなら使節が派遣先で行う支援内容を定義する
static void Callback(int i)
{
Console.WriteLine("Current counter is " + i);
}
}
public class SampleClass
{
//①デリゲートの定義
// ※例えるなら他組織(クラス)から送り込まれる使節
public delegate void Callback(int i);
//②引数にデリゲートを与えます
public void LoopPrint(Callback callback)
{
//何かしらの処理
for (int i = 0; i < 2000; i++)
{
//③デリゲートが参照する関数を呼び出します
//(ここがコールバックに相当します)
callback(i);
}
}
}
}
(図115)実行結果
