Différence entre les événements et les delegates et leurs applications respectives

Je ne vois aucun avantage à utiliser les événements plutôt que les delegates syntaxiques. Je suis peut-être mal compris, mais il semble que cet événement ne soit qu’un espace réservé aux delegates.

Voulez-vous m’expliquer les différences et quand utiliser lesquelles? Quels sont les avantages et les inconvénients? Notre code est fortement ancré dans les événements et je veux aller au fond des choses.

Quand utiliseriez-vous des delegates pour des événements et vice versa? Veuillez indiquer votre expérience réelle avec les deux, par exemple dans le code de production.

    Du sharepoint vue technique, d’autres réponses ont été apscopes aux différences.

    Du sharepoint vue de la sémantique, les événements sont des actions déclenchées par un object lorsque certaines conditions sont remplies. Par exemple, ma classe Stock a une propriété appelée Limit, et elle déclenche un événement lorsque les cours des actions atteignent la limite. Cette notification est effectuée via un événement. Que les utilisateurs se soucient réellement de cet événement et s’y abonne ne soit pas du ressort de la classe propriétaire.

    Un délégué est un terme plus générique pour décrire une construction similaire à un pointeur en C / C ++. Tous les delegates dans .Net sont des delegates à la multidiffusion. Du sharepoint vue de la sémantique, ils sont généralement utilisés comme une sorte de saisie. En particulier, ils constituent un moyen idéal pour mettre en œuvre le modèle de stratégie . Par exemple, si je veux sortinger une liste d’objects, je peux fournir une stratégie de comparaison à la méthode pour indiquer à l’implémentation comment comparer deux objects.

    J’ai utilisé les deux méthodes dans le code de production. Des tonnes de mes objects de données avertissent lorsque certaines propriétés sont remplies. Dans l’exemple le plus simple, chaque fois qu’une propriété change, un événement PropertyChanged est déclenché (voir Interface INotifyPropertyChanged). J’ai utilisé des delegates dans le code pour fournir différentes stratégies pour transformer certains objects en chaîne. Cet exemple particulier était une liste de mises en œuvre ToSsortingng () glorifiée pour un type d’object particulier à afficher aux utilisateurs.

    L’ event mot clé est un modificateur de scope pour les delegates de multidiffusion. Les différences pratiques entre ceci et la simple déclaration d’un délégué multicast sont les suivantes:

    • Vous pouvez utiliser event dans une interface.
    • L’access à l’invocation du délégué multidiffusion est limité à la classe déclarante. Le comportement est comme si le délégué était privé pour l’appel. Aux fins de l’affectation, l’access est spécifié par un modificateur d’access explicite (par exemple, public event ).

    En guise d’intérêt, vous pouvez appliquer + et - aux delegates de multidiffusion, et c’est la base de la syntaxe += et -= pour l’affectation combinée des delegates aux événements. Ces trois extraits sont équivalents:

     B = new EventHandler(this.MethodB); C = new EventHandler(this.MethodC); A = B + C; 

    Exemple deux, illustrant à la fois l’affectation directe et l’affectation de combinaison.

     B = new EventHandler(this.MethodB); C = new EventHandler(this.MethodC); A = B; A += C; 

    Troisième exemple: une syntaxe plus familière. Vous connaissez probablement l’affectation de null pour supprimer tous les gestionnaires.

     B = new EventHandler(this.MethodB); C = new EventHandler(this.MethodC); A = null; A += B; A += C; 

    Comme les propriétés, les événements ont une syntaxe complète que personne n’utilise jamais. Ce:

     class myExample { internal EventHandler eh; public event EventHandler OnSubmit { add { eh = Delegate.Combine(eh, value) as EventHandler; } remove { eh = Delegate.Remove(eh, value) as EventHandler; } } ... } 

    … fait exactement la même chose que ceci:

     class myExample { public event EventHandler OnSubmit; } 

    Les méthodes d’ajout et de suppression sont plus évidentes dans la syntaxe plutôt utilisée que VB.NET utilise (pas de surcharge d’opérateur).

    Les événements sont le sucre syntaxique. Ils sont délicieux. Quand je vois un événement, je sais quoi faire. Quand je vois un délégué, je n’en suis pas si sûr.

    La combinaison d’événements avec des interfaces (plus de sucre) en fait une collation qui met l’eau à la bouche. Les delegates et les classes abstraites virtuelles pures sont beaucoup moins appétissantes.

    Les événements sont marqués comme tels dans les métadonnées. Cela permet aux concepteurs de Windows Forms ou ASP.NET de distinguer les événements des simples propriétés du type délégué et de les prendre en charge de manière appropriée (en les affichant spécifiquement dans l’onglet Evénements de la fenêtre Propriétés).

    Une autre différence avec une propriété de type délégué est que les utilisateurs peuvent uniquement append et supprimer des gestionnaires d’événements, alors qu’avec une propriété de type délégué, ils peuvent définir la valeur:

     someObj.SomeCallback = MyCallback; // okay, replaces any existing callback someObj.SomeEvent = MyHandler; // not okay, must use += instead 

    Cela permet d’isoler les abonnés aux événements: je peux append mon gestionnaire à un événement et vous pouvez append votre gestionnaire au même événement, et vous n’écraserez pas accidentellement mon gestionnaire.

    Edit # 1 Quand utiliseriez-vous des delegates pour des événements et des vsversa? Veuillez indiquer votre expérience réelle avec les deux, par exemple dans le code de production.

    Lorsque je conçois mes propres API, je définis des delegates transmis en tant que parameters aux méthodes ou aux constructeurs de classes:

    • Ainsi, une méthode peut implémenter un modèle simple de “méthode de modèle” (par exemple, les delegates de Predicate et d’ Action sont transmis aux classes de collections génériques .Net)
    • Ou pour que la classe puisse faire un “rappel” (typiquement un rappel à une méthode de la classe qui l’a créée).

    Ces delegates ne sont généralement pas facultatifs à l’exécution (c. à-d. Ne doivent pas être null ).

    Je n’ai pas tendance à utiliser les événements; mais là où j’utilise des événements, je les utilise pour signaler éventuellement des événements à zéro, un ou plusieurs clients susceptibles d’ être intéressés, c’est-à-dire quand une classe (par exemple, la classe System.Windows.Form ) doit exister et s’exécuter ou non, un client a ajouté un gestionnaire d’événement à son événement (par exemple, l’événement ‘mouse down’ du formulaire existe, mais il est facultatif qu’un client externe souhaite installer un gestionnaire d’événement sur cet événement).

    Bien que les événements soient généralement implémentés avec des delegates multidiffusion, il n’est pas nécessaire qu’ils soient utilisés de la même manière. Si une classe expose un événement, cela signifie que la classe expose deux méthodes. Leurs significations sont, en substance:

    1. Voici un délégué. S’il vous plaît invoquez-le quand quelque chose d’intéressant se produit.
    2. Voici un délégué. Vous devriez détruire toute référence à celle-ci dès que possible (et ne plus l’appeler).

    La manière la plus courante pour une classe de gérer un événement qu’elle expose consiste à définir un délégué de multidiffusion et à append / supprimer tous les delegates transmis aux méthodes ci-dessus, mais il n’est pas nécessaire qu’ils fonctionnent de cette manière. Malheureusement, l’architecture des événements ne parvient pas à rendre certaines choses plus propres (par exemple, si la méthode de souscription retourne un MethodInvoker, qui serait conservé par l’abonné; pour désabonner un événement, il suffit d’appeler la méthode renvoyée). sont de loin l’approche la plus courante.

    pour comprendre les différences, vous pouvez regarder ces 2 exemples

    Exemple avec des delegates (action dans ce cas qui est une sorte de délégué qui ne renvoie pas de valeur)

     public class Animal { public Action Run {get; set;} public void RaiseEvent() { if (Run != null) { Run(); } } } 

    pour utiliser le délégué, vous devriez faire quelque chose comme ça

     Animale animal= new Animal(); animal.Run += () => Console.WriteLine("I'm running"); animal.Run += () => Console.WriteLine("I'm still running") ; animal.RaiseEvent(); 

    Ce code fonctionne bien mais vous pourriez avoir des points faibles.

    Par exemple si j’écris ceci

     animal.Run += () => Console.WriteLine("I'm running"); animal.Run += () => Console.WriteLine("I'm still running"); animal.Run = () => Console.WriteLine("I'm sleeping") ; 

    avec la dernière ligne de code, j’avais remplacé les comportements précédents avec un seul manquant + (j’ai utilisé + au lieu de += )

    Un autre point faible est que chaque classe qui utilise votre classe Animal peut élever RaiseEvent l’appelant simplement animal.RaiseEvent() .

    Pour éviter ces points faibles, vous pouvez utiliser des events dans c #.

    Votre classe d’animaux changera de cette façon

     public class ArgsSpecial :EventArgs { public ArgsSpecial (ssortingng val) { Operation=val; } public ssortingng Operation {get; set;} } public class Animal { public event EventHandler Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it public void RaiseEvent() { Run(this, new ArgsSpecial("Run faster")); } } 

    appeler des événements

      Animale animal= new Animal(); animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation); animal.RaiseEvent(); 

    Différences:

    1. Vous n’utilisez pas une propriété publique mais un champ public (avec des événements, le compilateur protège vos champs contre les access non désirés)
    2. Les événements ne peuvent pas être directement affectés. Dans ce cas, vous ne pouvez pas faire l’erreur précédente que j’ai montrée en remplaçant le comportement.
    3. Personne en dehors de votre classe ne peut organiser l’événement.
    4. Les événements peuvent être inclus dans une déclaration d’interface, alors qu’un champ ne peut pas

    Remarques

    EventHandler est déclaré comme délégué suivant:

     public delegate void EventHandler (object sender, EventArgs e) 

    il faut un émetteur (de type object) et des arguments d’événement. L’expéditeur est nul s’il provient de méthodes statiques.

    Vous pouvez également utiliser EventHAndler place de cet exemple qui utilise EventHandler

    référez-vous ici pour la documentation sur EventHandler

    Bien que je n’ai aucune raison technique pour cela, j’utilise les événements dans un code de style d’interface utilisateur, en d’autres termes, dans les niveaux supérieurs du code, et j’utilise des delegates pour une logique plus profonde dans le code. Comme je le dis, vous pouvez utiliser l’un ou l’autre, mais je trouve que ce modèle d’utilisation est logiquement sonore, sinon, il aide à documenter les types de rappels et leur hiérarchie.


    Edit: Je pense que la différence dans les modèles d’utilisation serait que, je trouve parfaitement acceptable d’ignorer les événements, ce sont des hooks / stubs, si vous avez besoin de connaître l’événement, écoutez-les, si vous ne vous souciez pas l’événement l’ignore juste. C’est pourquoi je les utilise pour l’interface utilisateur, en quelque sorte le style d’événement Javascript / Browser. Cependant, lorsque j’ai un délégué, je m’attends vraiment à ce que quelqu’un s’occupe de la tâche du délégué et lance une exception s’il n’est pas géré.

    La différence entre les événements et les delegates est beaucoup plus petite que ce que je pensais. Je viens de poster une vidéo YouTube super courte sur le sujet: https://www.youtube.com/watch?v=el-kKK-7SBU

    J’espère que cela t’aides!

    Si nous utilisons uniquement des delegates à la place d’Events, l’abonné a la possibilité de cloner (), invoquez () le délégué lui-même, comme indiqué ci-dessous dans l’image. Ce qui n’est pas correct

    entrer la description de l'image ici

    C’est la différence principale b / w événement et délégué. l’abonné n’a qu’un seul droit, à savoir écouter les événements

    La classe ConsoleLog souscrit aux événements du journal via EventLogHandler

     public class ConsoleLog { public ConsoleLog(Operation operation) { operation.EventLogHandler += print; } public void print(ssortingng str) { Console.WriteLine("write on console : " + str); } } 

    La classe FileLog souscrit aux événements du journal via EventLogHandler

     public class FileLog { public FileLog(Operation operation) { operation.EventLogHandler += print; } public void print(ssortingng str) { Console.WriteLine("write in File : " + str); } } 

    La classe d’opération publie les événements de journal

     public delegate void logDelegate(ssortingng str); public class Operation { public event logDelegate EventLogHandler; public Operation() { new FileLog(this); new ConsoleLog(this); } public void DoWork() { EventLogHandler.Invoke("somthing is working"); } }