デリゲートDelegates

デリゲートがシナリオの他の言語を有効にする、C、pascal 形式、および Modula--などの関数ポインターとしました。Delegates enable scenarios that other languages—such as C++, Pascal, and Modula -- have addressed with function pointers. ただし、C++ の関数ポインターとは異なりデリゲートはオブジェクト指向では完全に、C++ メンバー関数へのポインターとは異なり、デリゲートにはオブジェクトのインスタンスとメソッドの両方をカプセル化します。Unlike C++ function pointers, however, delegates are fully object oriented, and unlike C++ pointers to member functions, delegates encapsulate both an object instance and a method.

デリゲートの宣言は、クラスから派生したクラスを定義します。System.Delegateします。A delegate declaration defines a class that is derived from the class System.Delegate. デリゲートのインスタンスでは、呼び出し可能なエンティティと呼ばれますがそれぞれ 1 つまたは複数のメソッドの一覧は、呼び出しリストをカプセル化します。A delegate instance encapsulates an invocation list, which is a list of one or more methods, each of which is referred to as a callable entity. インスタンスのメソッドを呼び出し可能なエンティティから成るインスタンスとそのインスタンスのメソッド。For instance methods, a callable entity consists of an instance and a method on that instance. 静的メソッドの呼び出し可能なエンティティは、メソッドだけで構成されます。For static methods, a callable entity consists of just a method. 適切な一連の引数を含むデリゲート インスタンスを呼び出すと、指定した引数のセットを呼び出すときに、デリゲートの呼び出し可能なエンティティ。Invoking a delegate instance with an appropriate set of arguments causes each of the delegate's callable entities to be invoked with the given set of arguments.

Delegate インスタンスの興味深く有用なプロパティを把握したりしない気にカプセル化します。 メソッドのクラスこれらのメソッドを互換性のあることが重要な (デリゲートの宣言) で、デリゲートの型。An interesting and useful property of a delegate instance is that it does not know or care about the classes of the methods it encapsulates; all that matters is that those methods be compatible (Delegate declarations) with the delegate's type. これは、ため、デリゲートを「匿名」の呼び出しに最適です。This makes delegates perfectly suited for "anonymous" invocation.

デリゲートの宣言Delegate declarations

A delegate_declarationは、 type_declaration (入力宣言) 新しいデリゲート型を宣言します。A delegate_declaration is a type_declaration (Type declarations) that declares a new delegate type.

delegate_declaration
    : attributes? delegate_modifier* 'delegate' return_type
      identifier variant_type_parameter_list?
      '(' formal_parameter_list? ')' type_parameter_constraints_clause* ';'
    ;

delegate_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | delegate_modifier_unsafe
    ;

同じ修飾子をデリゲート宣言内で複数回のコンパイル時エラーになります。It is a compile-time error for the same modifier to appear multiple times in a delegate declaration.

new修飾子がデリゲートでのみ許可されている別の種類内で宣言されている場合、そのようなデリゲートを指定しますを非表示に継承されたメンバーを同じ名前で」の説明に従ってnew 修飾子します。The new modifier is only permitted on delegates declared within another type, in which case it specifies that such a delegate hides an inherited member by the same name, as described in The new modifier.

publicprotectedinternal、およびprivate修飾子はデリゲート型のアクセシビリティを制御します。The public, protected, internal, and private modifiers control the accessibility of the delegate type. デリゲートの宣言が発生したコンテキストに応じてこれらの修飾子の一部は使用できません (宣言されたアクセシビリティ)。Depending on the context in which the delegate declaration occurs, some of these modifiers may not be permitted (Declared accessibility).

デリゲートの型名が識別子します。The delegate's type name is identifier.

省略可能なformal_parameter_list 、デリゲートのパラメーターを指定し、 return_typeデリゲートの戻り値の型を示します。The optional formal_parameter_list specifies the parameters of the delegate, and return_type indicates the return type of the delegate.

省略可能なvariant_type_parameter_list (バリアント型パラメーター リスト)、デリゲート自体の型パラメーターを指定します。The optional variant_type_parameter_list (Variant type parameter lists) specifies the type parameters to the delegate itself.

デリゲート型の戻り値の型はいずれかである必要がありますvoid、または出力セーフ (差異の安全性)。The return type of a delegate type must be either void, or output-safe (Variance safety).

デリゲート型のすべての正式なパラメーター型は、入力の安全なである必要があります。All the formal parameter types of a delegate type must be input-safe. また、outまたはrefパラメーターの型は出力セーフにもあります。Additionally, any out or ref parameter types must also be output-safe. 注もoutパラメーターを基になる実行プラットフォームの制限により、入力セーフである必要があります。Note that even out parameters are required to be input-safe, due to a limitation of the underlying execution platform.

C# のデリゲート型がそれに相当しない構造的に等しい名前を付けます。Delegate types in C# are name equivalent, not structurally equivalent. 具体的には、同じパラメーターを持つ 2 つの異なるデリゲート型では、一覧表示し、型が異なるデリゲート型と見なされますを返します。Specifically, two different delegate types that have the same parameter lists and return type are considered different delegate types. ただし、2 つの異なるが、構造的に等しいデリゲート型のインスタンスが等しいと見なさ比較可能性があります (デリゲート等値演算子)。However, instances of two distinct but structurally equivalent delegate types may compare as equal (Delegate equality operators).

例:For example:

delegate int D1(int i, double d);

class A
{
    public static int M1(int a, double b) {...}
}

class B
{
    delegate int D2(int c, double d);
    public static int M1(int f, double g) {...}
    public static void M2(int k, double l) {...}
    public static int M3(int g) {...}
    public static void M4(int g) {...}
}

メソッドA.M1B.M1デリゲート型と互換性のあるD1D2があるため、型とパラメーター リストが同じ戻り値ただし、これらのデリゲート型が解除されるため、2 つのさまざまな種類を、。交換できます。The methods A.M1 and B.M1 are compatible with both the delegate types D1 and D2 , since they have the same return type and parameter list; however, these delegate types are two different types, so they are not interchangeable. メソッドB.M2B.M3、およびB.M4デリゲート型と互換性がないD1D2異なる戻り値の型またはパラメーター リストがあるため、します。The methods B.M2, B.M3, and B.M4 are incompatible with the delegate types D1 and D2, since they have different return types or parameter lists.

その他のジェネリック型の宣言のように構築されたデリゲート型を作成する型引数を指定する必要があります。Like other generic type declarations, type arguments must be given to create a constructed delegate type. パラメーターの型と構築されたデリゲート型の戻り値の型は、構築されたデリゲート型の対応する型引数をデリゲートの宣言で型パラメーターごとの代入することによって作成されます。The parameter types and return type of a constructed delegate type are created by substituting, for each type parameter in the delegate declaration, the corresponding type argument of the constructed delegate type. 結果として得られる戻り値の型とパラメーターの型は、構築されたデリゲート型と互換性のあるどのような方法の決定に使用されます。The resulting return type and parameter types are used in determining what methods are compatible with a constructed delegate type. 例:For example:

delegate bool Predicate<T>(T value);

class X
{
    static bool F(int i) {...}
    static bool G(string s) {...}
}

メソッドX.Fデリゲート型と互換性がPredicate<int>メソッドとX.Gデリゲート型と互換性がPredicate<string>します。The method X.F is compatible with the delegate type Predicate<int> and the method X.G is compatible with the delegate type Predicate<string> .

デリゲート型を宣言する唯一の方法を使用して、 delegate_declarationします。The only way to declare a delegate type is via a delegate_declaration. デリゲートの型から派生したクラス型は、System.Delegateします。A delegate type is a class type that is derived from System.Delegate. デリゲート型は暗黙的にsealedので、任意の型をデリゲート型から派生することはできません。Delegate types are implicitly sealed, so it is not permissible to derive any type from a delegate type. デリゲート以外のクラス型を派生させるにはもSystem.Delegateします。It is also not permissible to derive a non-delegate class type from System.Delegate. なおSystem.Delegateデリゲートの型自体は、すべてのデリゲート型の派生元クラス型です。Note that System.Delegate is not itself a delegate type; it is a class type from which all delegate types are derived.

C# のデリゲートの特別な構文を提供しますインスタンス化および呼び出し。C# provides special syntax for delegate instantiation and invocation. インスタンス化を除き、クラスまたはクラスのインスタンスに適用できるすべての操作も適用できますデリゲート クラスまたはインスタンスにそれぞれします。Except for instantiation, any operation that can be applied to a class or class instance can also be applied to a delegate class or instance, respectively. 特にのメンバーにアクセスすることは、System.Delegate通常メンバー アクセス構文を使用しました。In particular, it is possible to access members of the System.Delegate type via the usual member access syntax.

デリゲートのインスタンスによってカプセル化されるメソッドのセットには、呼び出しリストは呼び出されます。The set of methods encapsulated by a delegate instance is called an invocation list. デリゲートのインスタンスが作成されたとき (デリゲートの互換性) 1 つのメソッドから、そのメソッドをカプセル化し、呼び出しリストには、1 つのエントリが含まれています。When a delegate instance is created (Delegate compatibility) from a single method, it encapsulates that method, and its invocation list contains only one entry. ただし、2 つの null でないデリゲート インスタンスを組み合わせると、それぞれの呼び出しリストは--の順序で連結左のオペランドから - 右側のオペランドを 2 つ以上のエントリが含まれる新しい呼び出しリストを形成します。However, when two non-null delegate instances are combined, their invocation lists are concatenated -- in the order left operand then right operand -- to form a new invocation list, which contains two or more entries.

バイナリを使用してデリゲートを組み合わせる+(加算演算子) と+=演算子 (複合代入)。Delegates are combined using the binary + (Addition operator) and += operators (Compound assignment). デリゲートは、バイナリを使用して、デリゲートの組み合わせから削除できる-(減算演算子) と-=演算子 (複合代入)。A delegate can be removed from a combination of delegates, using the binary - (Subtraction operator) and -= operators (Compound assignment). デリゲートが等しいかどうかを比較できます (デリゲート等値演算子)。Delegates can be compared for equality (Delegate equality operators).

次の例は、いくつかのデリゲートのインスタンスを作成し、対応する呼び出しリストします。The following example shows the instantiation of a number of delegates, and their corresponding invocation lists:

delegate void D(int x);

class C
{
    public static void M1(int i) {...}
    public static void M2(int i) {...}

}

class Test
{
    static void Main() {
        D cd1 = new D(C.M1);      // M1
        D cd2 = new D(C.M2);      // M2
        D cd3 = cd1 + cd2;        // M1 + M2
        D cd4 = cd3 + cd1;        // M1 + M2 + M1
        D cd5 = cd4 + cd3;        // M1 + M2 + M1 + M1 + M2
    }

}

ときにcd1cd2はそれぞれ 1 つのメソッドをカプセル化をインスタンス化します。When cd1 and cd2 are instantiated, they each encapsulate one method. ときにcd3は 2 つのメソッドの呼び出しリストをインスタンス化がM1M2点で、注文します。When cd3 is instantiated, it has an invocation list of two methods, M1 and M2, in that order. cd4呼び出しリストが含まれていますM1M2、およびM1点で、注文します。cd4's invocation list contains M1, M2, and M1, in that order. 最後に、cd5の呼び出しリストが含まれていますM1M2M1M1、およびM2点で、注文します。Finally, cd5's invocation list contains M1, M2, M1, M1, and M2, in that order. (場合によっては、削除も) のデリゲートを組み合わせることの例については、次を参照してください。デリゲート呼び出しします。For more examples of combining (as well as removing) delegates, see Delegate invocation.

デリゲートの互換性Delegate compatibility

メソッドまたはデリゲートM互換性のあるデリゲート型でD次のすべてに該当する場合。A method or delegate M is compatible with a delegate type D if all of the following are true:

  • D Mパラメーター、および内の各パラメーターの個数が同じD同じrefまたはoutとの対応するパラメーター修飾子Mします。D and M have the same number of parameters, and each parameter in D has the same ref or out modifiers as the corresponding parameter in M.
  • 各値パラメーターの (パラメーターなしでrefまたはout修飾子)、id 変換 (恒等変換) または暗黙的な参照変換 (の暗黙の参照変換)パラメーター型から存在Dで対応するパラメーターの型にMします。For each value parameter (a parameter with no ref or out modifier), an identity conversion (Identity conversion) or implicit reference conversion (Implicit reference conversions) exists from the parameter type in D to the corresponding parameter type in M.
  • refまたはoutパラメーター、パラメーター入力Dでパラメーターの型と同じですMします。For each ref or out parameter, the parameter type in D is the same as the parameter type in M.
  • 戻り値の型からの id 列または暗黙的な参照変換が存在するMの戻り値の型をDします。An identity or implicit reference conversion exists from the return type of M to the return type of D.

デリゲートのインスタンス化Delegate instantiation

によって、デリゲートのインスタンスが作成された、 delegate_creation_expression (デリゲート作成式) またはデリゲート型に変換します。An instance of a delegate is created by a delegate_creation_expression (Delegate creation expressions) or a conversion to a delegate type. 新しく作成されたデリゲートのインスタンスは、いずれかを参照します。The newly created delegate instance then refers to either:

  • 参照される静的メソッド、 delegate_creation_expression、またはThe static method referenced in the delegate_creation_expression, or
  • ターゲット オブジェクト (することはできませんがnull) インスタンス メソッドで参照されていると、 delegate_creation_expression、またはThe target object (which cannot be null) and instance method referenced in the delegate_creation_expression, or
  • 他のデリゲート。Another delegate.

例:For example:

delegate void D(int x);

class C
{
    public static void M1(int i) {...}
    public void M2(int i) {...}
}

class Test
{
    static void Main() { 
        D cd1 = new D(C.M1);        // static method
        C t = new C();
        D cd2 = new D(t.M2);        // instance method
        D cd3 = new D(cd2);        // another delegate
    }
}

インスタンス化すると、同じターゲット オブジェクトとメソッドを常にデリゲート インスタンス参照してください。Once instantiated, delegate instances always refer to the same target object and method. 2 つのデリゲートを組み合わせると、または 1 つは、別の独自の呼び出しリスト持つ新しいデリゲート結果から削除する場合に、注意してください。結合または削除のデリゲートの呼び出しリストが変更されません。Remember, when two delegates are combined, or one is removed from another, a new delegate results with its own invocation list; the invocation lists of the delegates combined or removed remain unchanged.

デリゲートの呼び出しDelegate invocation

C#、デリゲートの呼び出しの特別な構文を提供します。C# provides special syntax for invoking a delegate. 呼び出しリスト持つにはには、1 つのエントリが含まれています。 null でないデリゲート インスタンスが呼び出されると、同じ引数が与えられているし、参照先と同じ値を返しますでは、1 つのメソッドが呼び出されますメソッドにします。When a non-null delegate instance whose invocation list contains one entry is invoked, it invokes the one method with the same arguments it was given, and returns the same value as the referred to method. (を参照してくださいデリゲートの呼び出しデリゲートの呼び出しの詳細についてはします)。そのメソッドを直接呼び出した場合とに、デリゲートが呼び出されるメソッドに例外 catch 句の検索を続行場合は、このようなデリゲートの呼び出し中に例外が発生して、その例外が呼び出されたメソッド内でキャッチされない、委任するメソッドと呼ばれます。(See Delegate invocations for detailed information on delegate invocation.) If an exception occurs during the invocation of such a delegate, and that exception is not caught within the method that was invoked, the search for an exception catch clause continues in the method that called the delegate, as if that method had directly called the method to which that delegate referred.

順序で同期的に、呼び出しリストのメソッド呼び出すことによって、呼び出しリスト持つにはには、複数のエントリが含まれています。 デリゲートのインスタンスの呼び出しが行われます。Invocation of a delegate instance whose invocation list contains multiple entries proceeds by invoking each of the methods in the invocation list, synchronously, in order. そのために呼び出される各メソッドには、同じように、デリゲート インスタンスに指定された引数のセットが渡されます。Each method so called is passed the same set of arguments as was given to the delegate instance. このようなデリゲートの呼び出しには、参照パラメーターが含まれている場合 (パラメーターを参照して)、同じ変数への参照で各メソッドの呼び出しが行われます呼び出しリスト内の 1 つのメソッドでは、その変数への変更になります。呼び出しリスト メソッドをさらに表示されます。If such a delegate invocation includes reference parameters (Reference parameters), each method invocation will occur with a reference to the same variable; changes to that variable by one method in the invocation list will be visible to methods further down the invocation list. デリゲートの呼び出しには、出力パラメーターまたは戻り値が含まれている場合、最終的な値は、一覧の最後のデリゲートの呼び出しから取得されます。If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.

場合は、このようなデリゲートの呼び出しの処理中に例外が発生して、その例外が呼び出されたメソッド内でキャッチされない、デリゲートを呼び出したメソッドで例外 catch 句の検索を続行して、メソッドの後の部分呼び出しリストには呼び出されません。If an exception occurs during processing of the invocation of such a delegate, and that exception is not caught within the method that was invoked, the search for an exception catch clause continues in the method that called the delegate, and any methods further down the invocation list are not invoked.

値が null の結果の種類の例外では、デリゲート インスタンスを起動しようとしています。System.NullReferenceExceptionします。Attempting to invoke a delegate instance whose value is null results in an exception of type System.NullReferenceException.

次の例では、インスタンス化、結合、削除、およびデリゲートを呼び出す方法を示します。The following example shows how to instantiate, combine, remove, and invoke delegates:

using System;

delegate void D(int x);

class C
{
    public static void M1(int i) {
        Console.WriteLine("C.M1: " + i);
    }

    public static void M2(int i) {
        Console.WriteLine("C.M2: " + i);
    }

    public void M3(int i) {
        Console.WriteLine("C.M3: " + i);
    }
}

class Test
{
    static void Main() { 
        D cd1 = new D(C.M1);
        cd1(-1);                // call M1

        D cd2 = new D(C.M2);
        cd2(-2);                // call M2

        D cd3 = cd1 + cd2;
        cd3(10);                // call M1 then M2

        cd3 += cd1;
        cd3(20);                // call M1, M2, then M1

        C c = new C();
        D cd4 = new D(c.M3);
        cd3 += cd4;
        cd3(30);                // call M1, M2, M1, then M3

        cd3 -= cd1;             // remove last M1
        cd3(40);                // call M1, M2, then M3

        cd3 -= cd4;
        cd3(50);                // call M1 then M2

        cd3 -= cd2;
        cd3(60);                // call M1

        cd3 -= cd2;             // impossible removal is benign
        cd3(60);                // call M1

        cd3 -= cd1;             // invocation list is empty so cd3 is null

        cd3(70);                // System.NullReferenceException thrown

        cd3 -= cd1;             // impossible removal is benign
    }
}

ステートメントに示すようにcd3 += cd1;デリゲートで使用できる呼び出しリストを複数回です。As shown in the statement cd3 += cd1;, a delegate can be present in an invocation list multiple times. この場合は、単に呼び出されます 1 回出現ごと。In this case, it is simply invoked once per occurrence. このなどの呼び出しリストをそのデリゲートを削除すると、呼び出しリストで、最後に見つかったが実際に削除します。In an invocation list such as this, when that delegate is removed, the last occurrence in the invocation list is the one actually removed.

最後のステートメントの実行前にすぐにcd3 -= cd1;、デリゲートcd3空の呼び出しリストを参照します。Immediately prior to the execution of the final statement, cd3 -= cd1;, the delegate cd3 refers to an empty invocation list. 空のリストからデリゲートを削除する (または空のリストから、存在しないデリゲートを削除する) をしようとしていますが、エラーではありません。Attempting to remove a delegate from an empty list (or to remove a non-existent delegate from a non-empty list) is not an error.

生成される出力は次のとおりです。The output produced is:

C.M1: -1
C.M2: -2
C.M1: 10
C.M2: 10
C.M1: 20
C.M2: 20
C.M1: 20
C.M1: 30
C.M2: 30
C.M1: 30
C.M3: 30
C.M1: 40
C.M2: 40
C.M3: 40
C.M1: 50
C.M2: 50
C.M1: 60
C.M1: 60