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

デリゲートは、C および C++ の関数ポインターのようなメソッドを安全にカプセル化する型です。A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. ただし、C 関数ポインターとは異なり、デリゲートはオブジェクト指向で、タイプ セーフで、安全です。Unlike C function pointers, delegates are object-oriented, type safe, and secure. デリゲートの型は、デリゲートの名前によって定義されます。The type of a delegate is defined by the name of the delegate. 次の例では、引数として文字列を受け取り、void を返すメソッドをカプセル化できる Del という名前のデリゲートを宣言しています。The following example declares a delegate named Del that can encapsulate a method that takes a string as an argument and returns void:

public delegate void Del(string message);

デリゲート オブジェクトは、通常、デリゲートがラップするメソッドの名前を指定して構成されるか、匿名関数を使用して構成されます。A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with an anonymous function. デリゲートがインスタンス化されると、デリゲートに対するメソッドの呼び出しが、デリゲートからメソッドに渡されます。Once a delegate is instantiated, a method call made to the delegate will be passed by the delegate to that method. 呼び出し元によってデリゲートに渡されるパラメーターはメソッドに渡され、戻り値がある場合は、デリゲートによってメソッドから呼び出し元に返されます。The parameters passed to the delegate by the caller are passed to the method, and the return value, if any, from the method is returned to the caller by the delegate. これは、デリゲートの呼び出しと呼ばれます。This is known as invoking the delegate. インスタンス化されたデリゲートは、ラップされたメソッドそのものであるかのように呼び出すことができます。An instantiated delegate can be invoked as if it were the wrapped method itself. 例:For example:

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

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

デリゲート型は、.NET Framework の Delegate クラスから派生しています。Delegate types are derived from the Delegate class in the .NET Framework. デリゲート型は sealed (派生できません) であり、Delegate からカスタム クラスを派生することはできません。Delegate types are sealed—they cannot be derived from— and it is not possible to derive custom classes from Delegate. インスタンス化されたデリゲートはオブジェクトであるため、パラメーターとして渡したり、プロパティに割り当てたりすることができます。Because the instantiated delegate is an object, it can be passed as a parameter, or assigned to a property. これにより、メソッドは、パラメーターとしてデリゲートを受け入れ、後でデリゲートを呼び出すことができます。This allows a method to accept a delegate as a parameter, and call the delegate at some later time. これは非同期のコールバックと呼ばれ、長いプロセスの完了時に呼び出し元に通知する一般的な方法です。This is known as an asynchronous callback, and is a common method of notifying a caller when a long process has completed. デリゲートをこの方法で使用する場合、デリゲートを使用するコードは、使用されるメソッドの実装について認識している必要はありません。When a delegate is used in this fashion, the code using the delegate does not need any knowledge of the implementation of the method being used. 機能は、カプセル化インターフェイスが提供する機能に似ています。The functionality is similar to the encapsulation interfaces provide.

コールバックの別の一般的な使用方法は、カスタム比較メソッドの定義およびそのデリゲートの並べ替えメソッドへの引き渡しです。Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. これにより、呼び出し元のコードを並べ替えアルゴリズムの一部にすることができます。It allows the caller's code to become part of the sort algorithm. 次の例のメソッドは Del 型をパラメーターとして使用しています。The following example method uses the Del type as a parameter:

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

上記で作成したデリゲートをメソッドに渡すことができます。You can then pass the delegate created above to that method:

MethodWithCallback(1, 2, handler);

次の出力がコンソールに表示されます。and receive the following output to the console:

The number is: 3

抽象化としてデリゲートを使用する場合、MethodWithCallback がコンソールを直接呼び出す必要はありません。コンソールに留意して設計する必要はありません。Using the delegate as an abstraction, MethodWithCallback does not need to call the console directly—it does not have to be designed with a console in mind. MethodWithCallback は文字列を準備し、文字列を別のメソッドに渡すだけです。What MethodWithCallback does is simply prepare a string and pass the string to another method. これは、デリゲート メソッドが任意の数のパラメーターを使用できるため、特に強力です。This is especially powerful since a delegated method can use any number of parameters.

インスタンス メソッドをラップするようにデリゲートが構築された場合、デリゲートはインスタンスとメソッドの両方を参照します。When a delegate is constructed to wrap an instance method, the delegate references both the instance and the method. デリゲートはラップするメソッド以外のインスタンス型を認識しないため、デリゲート シグネチャと一致するオブジェクトにメソッドがある限り、どの型のオブジェクトでも参照できます。A delegate has no knowledge of the instance type aside from the method it wraps, so a delegate can refer to any type of object as long as there is a method on that object that matches the delegate signature. 静的メソッドをラップするようにデリゲートが構築された場合、デリゲートはそのメソッドのみを参照します。When a delegate is constructed to wrap a static method, it only references the method. 次に宣言の例を示します。Consider the following declarations:

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

以前に示した静的な DelegateMethod と共に、Del インスタンスによってラップできるメソッドが 3 つあります。Along with the static DelegateMethod shown previously, we now have three methods that can be wrapped by a Del instance.

デリゲートは、呼び出されたときに複数のメソッドを呼び出すことができます。A delegate can call more than one method when invoked. これはマルチキャスティングと呼ばれます。This is referred to as multicasting. デリゲートのメソッドの一覧 (呼び出しリスト) に追加のメソッドを追加するには、加算演算子または加算代入演算子 ('+' または '+=') を使用して 2 つのデリゲートを追加する必要があります。To add an extra method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the addition or addition assignment operators ('+' or '+='). 例:For example:

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

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

この時点で、allMethodsDelegate には、呼び出しリスト内の 3 つのメソッド (Method1Method2DelegateMethod) が含まれています。At this point allMethodsDelegate contains three methods in its invocation list—Method1, Method2, and DelegateMethod. 元の 3 つのデリゲートである d1d2、および d3 は変更されません。The original three delegates, d1, d2, and d3, remain unchanged. allMethodsDelegate が呼び出されると、すべての 3 つのメソッドが順に呼び出されます。When allMethodsDelegate is invoked, all three methods are called in order. デリゲートで参照パラメーターを使用する場合、参照は、3 つのメソッドに順番に渡され、1 つのメソッドによって行われた変更は、次のメソッドに示されます。If the delegate uses reference parameters, the reference is passed sequentially to each of the three methods in turn, and any changes by one method are visible to the next method. いずれかのメソッドがメソッド内でキャッチされない例外をスローした場合、デリゲートの呼び出し元に例外が渡され、呼び出しリスト内の後続のメソッドは呼び出されません。When any of the methods throws an exception that is not caught within the method, that exception is passed to the caller of the delegate and no subsequent methods in the invocation list are called. デリゲートに戻り値や out パラメーターがある場合、デリゲートは戻り値と最後に呼び出されたメソッドのパラメーターを返します。If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked. 呼び出しリストからメソッドを削除するには、減算演算子または減算代入演算子 (- または -=) を使います。To remove a method from the invocation list, use the subtraction or subtraction assignment operators (- or -=). 例:For example:

//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;

デリゲート型が System.Delegate から派生しているため、そのクラスで定義されるメソッドとプロパティはデリゲートで呼び出すことができます。Because delegate types are derived from System.Delegate, the methods and properties defined by that class can be called on the delegate. たとえば、デリゲートの呼び出しリスト内のメソッドの数を検索するには、次のように記述します。For example, to find the number of methods in a delegate's invocation list, you may write:

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

呼び出しリストに複数のメソッドがあるデリゲートは、MulticastDelegate のサブクラスである System.Delegate から派生します。Delegates with more than one method in their invocation list derive from MulticastDelegate, which is a subclass of System.Delegate. 上記のコードでは、両方のクラスが GetInvocationList をサポートしているため、いずれの場合も機能します。The above code works in either case because both classes support GetInvocationList.

マルチキャスト デリゲートは、イベント処理で広く使用されます。Multicast delegates are used extensively in event handling. イベント ソース オブジェクトはイベントを受け取るように登録されている受信者オブジェクトにイベント通知を送信します。Event source objects send event notifications to recipient objects that have registered to receive that event. イベントを登録するには、受信者は、イベントを処理するようにデザインされたメソッドを作成し、そのメソッドのデリゲートを作成してイベント ソースにデリゲートを渡します。To register for an event, the recipient creates a method designed to handle the event, then creates a delegate for that method and passes the delegate to the event source. イベントが発生すると、ソースがデリゲートを呼び出します。The source calls the delegate when the event occurs. デリゲートは、受信者のイベント処理メソッドを呼び出し、イベント データを配信します。The delegate then calls the event handling method on the recipient, delivering the event data. 特定のイベントのデリゲート型は、イベント ソースによって定義されます。The delegate type for a given event is defined by the event source. 詳細については、「イベント (C# プログラミング ガイド)」を参照してください。For more, see Events.

コンパイル時に割り当てられた 2 つの異なる型のデリゲートを比較すると、コンパイル エラーが発生します。Comparing delegates of two different types assigned at compile-time will result in a compilation error. デリゲート インスタンスが静的な System.Delegate 型の場合は、比較できますが、実行時に false が返されます。If the delegate instances are statically of the type System.Delegate, then the comparison is allowed, but will return false at run time. 例:For example:

delegate void Delegate1();
delegate void Delegate2();

static void method(Delegate1 d, Delegate2 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);
}

関連項目See also