DéléguésDelegates

Les délégués permettent aux scénarios que d’autres langages, tels que C++, Pascal et Modula, aient résolu les pointeurs de fonction.Delegates enable scenarios that other languages—such as C++, Pascal, and Modula -- have addressed with function pointers. Contrairement C++ aux pointeurs de fonction, toutefois, les délégués sont entièrement orientés C++ objet et contrairement aux pointeurs vers des fonctions membres, les délégués encapsulent à la fois une instance d’objet et une méthode.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.

Une déclaration Delegate définit une classe dérivée de la classe System.Delegate.A delegate declaration defines a class that is derived from the class System.Delegate. Une instance de délégué encapsule une liste d’appel, qui est une liste d’une ou plusieurs méthodes, chacune d’elles étant désignée sous le terme d’entité pouvant être appelée.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. Pour les méthodes d’instance, une entité pouvant être appelée se compose d’une instance et d’une méthode sur cette instance.For instance methods, a callable entity consists of an instance and a method on that instance. Pour les méthodes statiques, une entité pouvant être appelée se compose simplement d’une méthode.For static methods, a callable entity consists of just a method. L’appel d’une instance de délégué avec un jeu d’arguments approprié entraîne l’appel de chacune des entités pouvant être appelées par le délégué avec le jeu d’arguments donné.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.

Une propriété intéressante et utile d’une instance de délégué est qu’elle ne connaît pas ou ne tient pas compte des classes des méthodes qu’elle encapsule ; Il est important que ces méthodes soient compatibles (déclarations déléguées) avec le type du délégué.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. Les délégués sont alors parfaitement adaptés à l’appel « anonyme ».This makes delegates perfectly suited for "anonymous" invocation.

Déclarations de déléguéDelegate declarations

Un delegate_declaration est un type_declaration (déclarations de type) qui déclare un nouveau type délégué.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
    ;

Il s’agit d’une erreur au moment de la compilation pour que le même modificateur apparaisse plusieurs fois dans une déclaration Delegate.It is a compile-time error for the same modifier to appear multiple times in a delegate declaration.

Le modificateur de new est autorisé uniquement sur les délégués déclarés dans un autre type, auquel cas il spécifie qu’un tel délégué masque un membre hérité du même nom, comme décrit dans le nouveau modificateur.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.

Les modificateurs public, protected, internalet private contrôlent l’accessibilité du type délégué.The public, protected, internal, and private modifiers control the accessibility of the delegate type. En fonction du contexte dans lequel la déclaration du délégué se produit, certains de ces modificateurs peuvent ne pas être autorisés (accessibilité déclarée).Depending on the context in which the delegate declaration occurs, some of these modifiers may not be permitted (Declared accessibility).

Le nom de type du délégué est identifier.The delegate's type name is identifier.

Le formal_parameter_list facultatif spécifie les paramètres du délégué et return_type indique le type de retour du délégué.The optional formal_parameter_list specifies the parameters of the delegate, and return_type indicates the return type of the delegate.

Le variant_type_parameter_list facultatif (listes de paramètres de type Variant) spécifie les paramètres de type pour le délégué lui-même.The optional variant_type_parameter_list (Variant type parameter lists) specifies the type parameters to the delegate itself.

Le type de retour d’un type délégué doit être voidou sécurisé de sortie (lasécurité d’écart).The return type of a delegate type must be either void, or output-safe (Variance safety).

Tous les types de paramètres formels d’un type délégué doivent être de type sécurisé d’entrée.All the formal parameter types of a delegate type must be input-safe. En outre, tous les types de paramètres out ou ref doivent également être de type sécurisé de sortie.Additionally, any out or ref parameter types must also be output-safe. Notez que même les paramètres de out sont requis pour la sécurité d’entrée, en raison d’une limitation de la plateforme d’exécution sous-jacente.Note that even out parameters are required to be input-safe, due to a limitation of the underlying execution platform.

Les types délégués C# dans sont équivalents au nom, et non structurellement équivalents.Delegate types in C# are name equivalent, not structurally equivalent. Plus précisément, deux types délégués différents ayant les mêmes listes de paramètres et type de retour sont considérés comme des types délégués différents.Specifically, two different delegate types that have the same parameter lists and return type are considered different delegate types. Toutefois, les instances de deux types délégués distincts mais structurellement équivalents peuvent être considérées comme égales (opérateurs d’égalité de délégué).However, instances of two distinct but structurally equivalent delegate types may compare as equal (Delegate equality operators).

Exemple :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) {...}
}

Les méthodes A.M1 et B.M1 sont compatibles avec les types délégués D1 et D2, car ils ont le même type de retour et la même liste de paramètres ; Toutefois, ces types délégués sont de deux types différents. ils ne sont donc pas interchangeables.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. Les méthodes B.M2, B.M3et B.M4 sont incompatibles avec les types délégués D1 et D2, car ils ont des types de retour ou des listes de paramètres différents.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.

Comme d’autres déclarations de type générique, les arguments de type doivent être fournis pour créer un type délégué construit.Like other generic type declarations, type arguments must be given to create a constructed delegate type. Les types de paramètres et le type de retour d’un type délégué construit sont créés en substituant, pour chaque paramètre de type dans la déclaration du délégué, l’argument de type correspondant du type délégué construit.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. Le type de retour et les types de paramètres résultants sont utilisés pour déterminer quelles méthodes sont compatibles avec un type délégué construit.The resulting return type and parameter types are used in determining what methods are compatible with a constructed delegate type. Exemple :For example:

delegate bool Predicate<T>(T value);

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

La méthode X.F est compatible avec le type délégué Predicate<int> et la méthode X.G est compatible avec le type délégué 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> .

La seule façon de déclarer un type délégué est d’utiliser une delegate_declaration.The only way to declare a delegate type is via a delegate_declaration. Un type délégué est un type de classe dérivé de System.Delegate.A delegate type is a class type that is derived from System.Delegate. Les types délégués sont implicitement sealed. il n’est donc pas possible de dériver un type d’un type délégué.Delegate types are implicitly sealed, so it is not permissible to derive any type from a delegate type. Il n’est pas non plus possible de dériver un type de classe non déléguée à partir de System.Delegate.It is also not permissible to derive a non-delegate class type from System.Delegate. Notez que System.Delegate n’est pas lui-même un type délégué ; Il s’agit d’un type de classe dont tous les types délégués sont dérivés.Note that System.Delegate is not itself a delegate type; it is a class type from which all delegate types are derived.

C#fournit une syntaxe spéciale pour l’instanciation et l’appel de délégués.C# provides special syntax for delegate instantiation and invocation. À l’exception de l’instanciation, toute opération qui peut être appliquée à une classe ou une instance de classe peut également être appliquée à une instance ou une classe déléguée, respectivement.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. En particulier, il est possible d’accéder aux membres du type System.Delegate par le biais de la syntaxe d’accès aux membres habituelle.In particular, it is possible to access members of the System.Delegate type via the usual member access syntax.

L’ensemble de méthodes encapsulé par une instance de délégué est appelé une liste d’appel.The set of methods encapsulated by a delegate instance is called an invocation list. Lorsqu’une instance de délégué est créée (déléguer la compatibilité) à partir d’une seule méthode, elle encapsule cette méthode et sa liste d’appel contient une seule entrée.When a delegate instance is created (Delegate compatibility) from a single method, it encapsulates that method, and its invocation list contains only one entry. Toutefois, lorsque deux instances de délégués non NULL sont combinées, leurs listes d’appel sont concaténées, dans l’opérande de l’ordre de gauche, puis dans l’opérande de droite, pour former une nouvelle liste d’appel, qui contient au moins deux entrées.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.

Les délégués sont combinés à l’aide des opérateurs binaires + (opérateur d’addition) et += (assignation composée).Delegates are combined using the binary + (Addition operator) and += operators (Compound assignment). Un délégué peut être supprimé d’une combinaison de délégués à l’aide de l' - binaire (opérateur de soustraction) et -= opérateurs (assignation composée).A delegate can be removed from a combination of delegates, using the binary - (Subtraction operator) and -= operators (Compound assignment). Les délégués peuvent être comparés pour déterminer leur égalité (opérateurs d’égalité de délégué).Delegates can be compared for equality (Delegate equality operators).

L’exemple suivant illustre l’instanciation d’un certain nombre de délégués et les listes d’appel correspondantes :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
    }

}

Lorsque cd1 et cd2 sont instanciés, ils encapsulent chacun une méthode.When cd1 and cd2 are instantiated, they each encapsulate one method. Lorsque cd3 est instancié, il dispose d’une liste d’appel de deux méthodes, M1 et M2, dans cet ordre.When cd3 is instantiated, it has an invocation list of two methods, M1 and M2, in that order. la liste d’appel de cd4contient M1, M2et M1, dans cet ordre.cd4's invocation list contains M1, M2, and M1, in that order. Enfin, la liste d’appel de cd5contient M1, M2, M1, M1et M2, dans cet ordre.Finally, cd5's invocation list contains M1, M2, M1, M1, and M2, in that order. Pour obtenir plus d’exemples de combinaison (et de suppression) de délégués, consultez appel de délégué.For more examples of combining (as well as removing) delegates, see Delegate invocation.

Déléguer la compatibilitéDelegate compatibility

Une méthode ou un délégué M est compatible avec un type délégué D si toutes les conditions suivantes sont vraies :A method or delegate M is compatible with a delegate type D if all of the following are true:

  • D et M ont le même nombre de paramètres, et chaque paramètre dans D a les mêmes modificateurs ref ou out que le paramètre correspondant dans 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.
  • Pour chaque paramètre de valeur (paramètre sans ref ou modificateur de out), une conversion d’identité (conversion d’identité) ou une conversion de référence implicite (conversions de référence implicites) existe à partir du type de paramètre dans D vers le type de paramètre correspondant dans 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.
  • Pour chaque ref ou out paramètre, le type de paramètre dans D est le même que le type de paramètre dans M.For each ref or out parameter, the parameter type in D is the same as the parameter type in M.
  • Une conversion d’identité ou de référence implicite existe du type de retour de M au type de retour de D.An identity or implicit reference conversion exists from the return type of M to the return type of D.

Instanciation de déléguéDelegate instantiation

Une instance d’un délégué est créée par un delegate_creation_expression (expressions de création de délégué) ou une conversion vers un type délégué.An instance of a delegate is created by a delegate_creation_expression (Delegate creation expressions) or a conversion to a delegate type. L’instance de délégué nouvellement créée fait référence à l’une des deux :The newly created delegate instance then refers to either:

  • Méthode statique référencée dans le delegate_creation_expressionouThe static method referenced in the delegate_creation_expression, or
  • L’objet cible (qui ne peut pas être null) et la méthode d’instance référencée dans le delegate_creation_expression, ouThe target object (which cannot be null) and instance method referenced in the delegate_creation_expression, or
  • Autre délégué.Another delegate.

Exemple :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
    }
}

Une fois instanciés, les instances de délégué font toujours référence aux mêmes objet et méthode cible.Once instantiated, delegate instances always refer to the same target object and method. Rappelez-vous que lorsque deux délégués sont combinés, ou lorsqu’un nouveau délégué est supprimé d’un autre, un nouveau délégué est obtenu avec sa propre liste d’appel ; les listes d’appel des délégués combinés ou supprimés restent inchangées.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.

Appel de déléguéDelegate invocation

C#fournit une syntaxe spéciale pour appeler un délégué.C# provides special syntax for invoking a delegate. Lorsqu’une instance de délégué non null dont la liste d’appel contient une entrée est appelée, elle appelle la méthode à l’aide des mêmes arguments qu’elle a été donnée et retourne la même valeur que la méthode référencée.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. (Pour plus d’informations sur l’appel de délégué, consultez appel de délégué .) Si une exception se produit pendant l’appel d’un tel délégué et que cette exception n’est pas interceptée dans la méthode qui a été appelée, la recherche d’une clause catch d’exception continue dans la méthode qui a appelé le délégué, comme si cette méthode avait directement appelé la méthode à laquelle ce délégué a fait face.(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.

L’appel d’une instance de délégué dont la liste d’appel contient plusieurs entrées se poursuit en appelant chaque méthode de la liste d’appel, de manière synchrone, dans l’ordre.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. Chaque méthode appelée reçoit le même jeu d’arguments que celui qui a été donné à l’instance de délégué.Each method so called is passed the same set of arguments as was given to the delegate instance. Si un tel appel de délégué comprend des paramètres de référence (paramètres de référence), chaque appel de méthode se produit avec une référence à la même variable ; les modifications apportées à cette variable par une méthode dans la liste d’appel seront visibles par les méthodes plus loin dans la liste d’appel.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. Si l’appel de délégué comprend des paramètres de sortie ou une valeur de retour, la valeur finale provient de l’appel du dernier délégué de la liste.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.

Si une exception se produit pendant le traitement de l’appel d’un délégué de ce type, et si cette exception n’est pas interceptée dans la méthode qui a été appelée, la recherche d’une clause catch d’exception continue dans la méthode qui a appelé le délégué, et toutes les méthodes plus loin la liste d’appel n’est pas appelée.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.

Toute tentative d’appel d’une instance de délégué dont la valeur est null entraîne une exception de type System.NullReferenceException.Attempting to invoke a delegate instance whose value is null results in an exception of type System.NullReferenceException.

L’exemple suivant montre comment instancier, combiner, supprimer et appeler des délégués :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
    }
}

Comme indiqué dans l’instruction cd3 += cd1;, un délégué peut être présent plusieurs fois dans une liste d’appel.As shown in the statement cd3 += cd1;, a delegate can be present in an invocation list multiple times. Dans ce cas, elle est simplement appelée une fois par occurrence.In this case, it is simply invoked once per occurrence. Dans une liste d’appel telle que celle-ci, lorsque ce délégué est supprimé, la dernière occurrence dans la liste d’appel est celle qui est réellement supprimée.In an invocation list such as this, when that delegate is removed, the last occurrence in the invocation list is the one actually removed.

Juste avant l’exécution de l’instruction finale, cd3 -= cd1;, le délégué cd3 fait référence à une liste d’appel vide.Immediately prior to the execution of the final statement, cd3 -= cd1;, the delegate cd3 refers to an empty invocation list. Toute tentative de suppression d’un délégué d’une liste vide (ou de suppression d’un délégué inexistant d’une liste non vide) n’est pas une erreur.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.

La sortie produite est la suivante :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