次の方法で共有


デリゲートの使用 (C# プログラミング ガイド)

デリゲートは、C および C++ の関数ポインターと同様に、メソッドを安全にカプセル化する型です。 C 関数ポインターとは異なり、デリゲートはオブジェクト指向、型セーフ、およびセキュリティで保護されています。 次の例では、Callbackを引数として受け取り、void を返すメソッドをカプセル化できる、という名前のデリゲートを宣言します。

public delegate void Callback(string message);

デリゲート オブジェクトは通常、デリゲートがラップするメソッドの名前を指定するか、 ラムダ式を使用して構築されます。 この方法でインスタンス化されると、デリゲートを呼び出すことができます。 デリゲートを呼び出すと、デリゲート インスタンスにアタッチされているメソッドが呼び出されます。 呼び出し元によってデリゲートに渡されるパラメーターは、メソッドに渡されます。 デリゲートは、メソッドから戻り値 (存在する場合) を返します。 例えば次が挙げられます。

// Create a method for a delegate.
public static void DelegateMethod(string message)
{
    Console.WriteLine(message);
}
// Instantiate the delegate.
Callback handler = DelegateMethod;

// Call the delegate.
handler("Hello World");

デリゲート型は、.NET の Delegate クラスから派生します。 デリゲート型は シールされ、派生元にすることはできません。また、 Delegateからカスタム クラスを派生させることはできません。 インスタンス化されたデリゲートはオブジェクトであるため、引数として渡すか、プロパティに割り当てることができます。 メソッドは、デリゲートをパラメーターとして受け入れ、後でデリゲートを呼び出すことができます。 これは非同期コールバックと呼ばれ、長いプロセスが完了したときに呼び出し元に通知する一般的な方法です。 この方法でデリゲートを使用する場合、デリゲートを使用するコードでは、使用されているメソッドの実装に関する知識は必要ありません。 この機能は、カプセル化インターフェイスが提供する機能に似ています。

コールバックのもう 1 つの一般的な用途は、カスタム比較メソッドを定義し、そのデリゲートを並べ替えメソッドに渡すことです。 これにより、呼び出し元のコードが並べ替えアルゴリズムの一部になります。 次のメソッド例では、パラメーターとして Del 型を使用します。

public static void MethodWithCallback(int param1, int param2, Callback callback)
{
    callback("The number is: " + (param1 + param2).ToString());
}

その後、前の例で作成したデリゲートをそのメソッドに渡すことができます。

MethodWithCallback(1, 2, handler);

コンソールに次の出力を受け取ります。

The number is: 3

MethodWithCallback コンソールを直接呼び出す必要はありません。本体を念頭に置いて設計する必要はありません。 MethodWithCallbackは、文字列を準備し、その文字列を別のメソッドに渡すことです。 委任されたメソッドでは、任意の数のパラメーターを使用できます。

デリゲートがインスタンス メソッドをラップするように構築されると、デリゲートはインスタンスとメソッドの両方を参照します。 デリゲートは、ラップするメソッド以外のインスタンス型を認識しません。 デリゲートは、デリゲート シグネチャに一致するメソッドがオブジェクトに存在する限り、任意の種類のオブジェクトを参照できます。 静的メソッドをラップするようにデリゲートが構築されると、そのメソッドのみが参照されます。 次の宣言について考えてみましょう。

public class MethodClass
{
    public void Method1(string message) { }
    public void Method2(string message) { }
}

前に示した静的 DelegateMethod と共に、 Del インスタンスでラップできる 3 つのメソッドが用意されました。

デリゲートは、呼び出されたときに、マルチキャスト機能を使用して複数のメソッドを呼び出すことができます。 デリゲートのメソッドの一覧 (呼び出しリスト) に追加のメソッドを追加するには、加算代入演算子または加算代入演算子 ('+' または '+=') を使用して 2 つのデリゲートを追加する必要があります。 例えば次が挙げられます。

var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;

//Both types of assignment are valid.
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;

allMethodsDelegateには、呼び出しリストに 3 つのメソッド (Method1Method2DelegateMethod) が含まれています。 元の 3 つのデリゲート ( d1d2d3) は変更されません。 allMethodsDelegateが呼び出されると、3 つのメソッドすべてが順番に呼び出されます。 デリゲートが参照パラメーターを使用する場合、参照は 3 つの各メソッドに順番に渡され、1 つのメソッドによる変更は次のメソッドに表示されます。 いずれかのメソッドがメソッド内でキャッチされない例外をスローすると、その例外はデリゲートの呼び出し元に渡されます。 呼び出しリスト内の後続のメソッドは呼び出されません。 デリゲートに戻り値や出力パラメーターがある場合は、最後に呼び出されたメソッドの戻り値とパラメーターを返します。 呼び出しリストからメソッドを削除するには、 減算または減算代入演算子 (- または -=) を使用します。 例えば次が挙げられます。

//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;

デリゲート型は System.Delegateから派生しているため、そのクラスで定義されているメソッドとプロパティをデリゲートで呼び出すことができます。 たとえば、デリゲートの呼び出しリスト内のメソッドの数を見つけるには、次のように記述できます。

int invocationCount = d1.GetInvocationList().GetLength(0);

呼び出しリストに複数のメソッドを持つデリゲートは、MulticastDelegateのサブクラスであるSystem.Delegateから派生します。 両方のクラスが GetInvocationListをサポートしているため、上記のコードはどちらの場合も機能します。

マルチキャスト デリゲートは、イベント処理で広く使用されます。 イベント ソース オブジェクトは、そのイベントを受信するために登録された受信者オブジェクトにイベント通知を送信します。 イベントに登録するために、受信者はイベントを処理するように設計されたメソッドを作成し、そのメソッドのデリゲートを作成して、デリゲートをイベント ソースに渡します。 ソースは、イベントが発生したときにデリゲートを呼び出します。 その後、デリゲートは受信者に対してイベント処理メソッドを呼び出し、イベント データを配信します。 イベント ソースは、特定のイベントのデリゲート型を定義します。 詳細については、「 イベント」を参照してください。

コンパイル時に割り当てられた 2 つの異なる型のデリゲートを比較すると、コンパイル エラーが発生します。 デリゲート インスタンスが System.Delegate型の静的な場合、比較は許可されますが、実行時に false が返されます。 例えば次が挙げられます。

delegate void Callback1();
delegate void Callback2();

static void method(Callback1 d, Callback2 e, System.Delegate f)
{
    // Compile-time error.
    Console.WriteLine(d == e);

    // OK at compile-time. False if the run-time type of f
    // is not the same as that of d.
    Console.WriteLine(d == f);
}

こちらも参照ください