2010-11-29 12 views
21

Possible en double:
Is there a downside to adding an anonymous empty delegate on event declaration?Est-ce une bonne pratique de définir un corps de délégué vide pour un événement?

est-il une bonne pratique de définir un corps délégué vide pour un événement afin que vous n'avez pas besoin de vous inquiéter soulever un événement qui n'a pas de gestionnaire d'événements ? (pas besoin de vérifier si l'événement est nul).

code comme ci-dessous:

public event EventHandler<LoadEventArgs> LoadedData = delegate { }; 
+1

Pas tout le monde est trop heureux à ce sujet, pour plus de détails vérifier ici: http://stackoverflow.com/questions/9033/hidden-features-of-c/9282#9282 – gjvdkamp

Répondre

36

J'ai certainement trouvé utile, oui. Il y aura un minuscule, petit coût de performance - mais l'avantage de la lisibilité pour ne pas avoir à effectuer le test de nullité en vaut la peine IMO.

Il est intéressant de souligner que c'est l'un des rares moments où il est bon d'utiliser une méthode anonyme plutôt que d'une expression lambda - sinon vous devez nommer les paramètres que vous allez ignorer, comme ceci:

public event EventHandler<LoadEventArgs> LoadedData = (sender, args) => {}; 

Je n'aime pas avoir à nommer des choses que je ne suis pas l'intention d'utiliser :)

+3

bien, vous pouvez cay '(_, __) => {} 'ce qui n'est pas trop mauvais que' delegate {} ' –

+1

Il y a maintenant un?. opérateur qui peut être utilisé au lieu d'effectuer des vérifications nulles, par ex. MyEvent? .Invoke(); Cela peut être une alternative utile. – person27

+1

@ Anon234_4521: En effet, selon https: //codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/- mais je ne vais pas mettre à jour tous mes messages d'il y a plusieurs années :) –

4

Je ne ferais pas cela.

Il y a deux raisons à cela. Tout d'abord, il est normal de simplement vérifier le gestionnaire pour null avant de l'appeler. Vous voyez cela partout, dans des exemples, dans la source de référence Microsoft et in the manuals. Deuxièmement, initialiser vos événements de cette manière alloue des objets inutiles lors de la création de votre classe. Cela mettra une pression mémoire supplémentaire sur votre application sans réel besoin. En effet:

public event EventHandler<LoadEventArgs> LoadedData = delegate { }; 

se traduit:

public event EventHandler<LoadEventArgs> LoadedData = new EventHandler<LoadEventArgs>delegate { }); 

Si vous ne le faites pas déjà, envelopper vos événements dans des méthodes spécifiques aide beaucoup:

public event EventHandler MyEvent; 

protected virtual void OnMyEvent(EventArgs e) 
{ 
    if (MyEvent != null) 
     MyEvent(this, e); 
} 

Vous pouvez faire ce fil de sécurité (r) en utilisant ce qui suit:

public event EventHandler MyEvent; 

protected virtual void OnMyEvent(EventArgs e) 
{ 
    var handler = MyEvent; 

    if (handler != null) 
     handler(this, e); 
} 
+7

Il va créer un seul objet supplémentaire qui va être partagé par toutes les instances, car le délégué n'accède à aucune variable capturée. (Pas garanti, mais le compilateur MS le fera.) Est-ce que ça va être important? J'en doute. Cependant, la chance de quelqu'un d'écrire la version non-thread-safe (selon votre premier extrait de code) est assez importante, IMO. Qu'ils se retrouvent avec une exception NullReferenceException ou non, qui sait ... mais vous pouvez parier que cela se passera sur un site client au lieu d'un test ... la mineure dégradation des performances vaut-elle vraiment le code supplémentaire? –

+1

@Jon Skeet - Cela dépend. Premièrement, la raison pour laquelle j'ai ajouté le deuxième extrait est spécifiquement pour cette raison (pensez que j'ai obtenu ce code à partir d'une réponse précédente de votre part :)). Cependant, plus souvent qu'autrement, les classes ne sont pas thread-safe pour commencer. Prenez par exemple 'Dictionary <,>'. N'essayez pas d'ajouter et de lire en même temps :). En ce qui concerne le nouveau «délégué», vous avez raison à ce sujet. Cependant, un nouveau EventHandler est créé pour chaque événement. 'MyEvent = delegate {}' se traduit par 'MyEvent = new EventHandler (delegate {})'. –

+0

Chaque événement créera un objet supplémentaire, oui. Sur l'ensemble de la durée de vie de l'application, je pense que je peux gérer "gaspiller" quelques centaines d'octets pour plusieurs événements. Notez que même si vous ne vous souciez pas de la sécurité des threads, l'utilisation de l'astuce "hand-handler" simplifie le code événementiel ... et c'est une chose de moins à considérer si vous voulez code thread-safe. –

1

Je n'utilise pas normalement C# mais cela me semble être une bonne pratique. Ceci est une application du manuel du modèle 'Null Object'. Comme indiqué, cela va coûter en termes de performance lorsque le délégué vide s'exécute réellement, mais gagne en termes de performance à chaque fois, quand vous n'avez pas besoin de vérifier un null explicite - donc cela devrait aussi être une performance de gain net - sage lorsque la fréquence des délégués vides est faible.