La vérification des délégués pour les nuls
J'ai lu l'Essentiel de C# 3.0, livre et je me demande si c'est une bonne façon de vérifier les délégués pour les nuls?:
class Thermostat
{
public delegate void TemperatureChangeHandler ( float newTemperature );
public TemperatureChangeHandler OnTemperatureChange { get; set; }
float currentTemperature;
public float CurrentTemperature
{
get { return this.currentTemperature; }
set
{
if ( currentTemperature != value )
{
currentTemperature = value;
TemperatureChangeHandler handler = OnTemperatureChange;
if ( handler != null )
{
handler ( value );
}
}
}
}
}
La solution des modifications si le type est immuable? J'ai pensé que peut-être avec l'immutabilité ne vous lancez pas dans cette filetage problème.
Ce type est immuable.
Merci, je ne pensais pas que ça à fond mais juste pensé que ça pourrait aider pour cette filetage cas.
Merci, je ne pensais pas que ça à fond mais juste pensé que ça pourrait aider pour cette filetage cas.
OriginalL'auteur Joan Venge | 2009-06-09
Vous devez vous connecter pour publier un commentaire.
D'origine (un peu inexact) Réponse:
Il y a eu beaucoup de discussions sur ce.
En bref: vous ne pouvez pas garantir que le gestionnaire sera valable même en faisant cela, copier/vérifier la valeur null/exécuter l'étape.
Le problème est que si OnTemperatureChange est pas enregistrée entre le moment où vous le copier, et le temps que vous exécuter la copie, alors il est probablement vrai que vous ne voulez pas l'auditeur à être exécuté de toute façon.
Vous pouvez tout aussi bien faire:
Et gérer une référence nulle exception.
J'ajoute parfois un gestionnaire par défaut qui ne fait rien, juste pour empêcher la référence nulle exception, mais qui ajoute l'impact de la performance tout à fait au sérieux, surtout dans le cas où il n'existe aucun autre gestionnaire d'inscrits.
Mise à jour 2014-07-10:
Reporter à Eric Lippert.
Ma réponse initiale a fait allusion à l'aide de gestionnaires par défaut, mais je n'ai pas recommander l'utilisation d'une variable temp, dont je suis maintenant d'accord en tant que bonne pratique également, par l'article.
Donc en gros si je comprends bien, la solution la plus simple fonctionne en mono-thread code tout le temps, mais il n'est pas garanti dans le code multithread, et il n'y a pas de solution simple?
Yerp, multi threaded code est vraiment difficile à obtenir le droit à cet égard, voir: stackoverflow.com/questions/786383/c-events-and-thread-safety
Les gestionnaires d'événements sont censés gérer harmonieusement être appelé même après qu'ils aient été ou non. L'objet le gestionnaire d'événements est également pas être nettoyés aussi longtemps que le délégué contient une référence à elle. En bref, après la création d'un immuable copie d'un délégué d'événement et de les vérifier pour les nuls, il est complètement sûr pour exécuter la copie. Toutes les erreurs qui découlent de cette situation sont les gestionnaires de la faute et ils doivent être corrigées.
Je pense que Eric Lipperts réponse à la même question est un peu plus clair? blogs.msdn.com/b/ericlippert/archive/2009/04/29/...
OriginalL'auteur John Weldon
Il est une raison le code que vous avez donné est recommandé C. Ross version. Cependant, John est également à bon droit qu'il y a encore un autre problème, si un événement est enregistré dans l'intervalle. Le blog, j'ai lié recommande que le gestionnaire de s'assurer qu'ils peuvent être appelés, même après être non.
OriginalL'auteur Matthew Flaschen
Tout d'abord, vous n'êtes pas réellement de la publication d'un événement - donc pour le moment, votre code est "à risque" de personnes gâcher complètement. Il doit être:
Le nom "CurrentTemperatureChanged" est important pour la liaison de données (il s'agit d'une convention que le moteur d'exécution utilise donné une propriété Toto, il va chercher les FooChanged). Cependant de l'OMI, ce devrait juste être régulier
EventHandler
. De liaison de données va chercherEventHandler
, mais le plus important: vous n'êtes pas réellement en donnant toutes les informations dans le cas où l'abonné ne peut déjà obtenir tout simplement en les regardantobj.CurrentTemperature
.Je vais donner le reste de la réponse en termes de
TemperatureChangeHandler
, mais je voudrais vous encourager (de nouveau) pour passer àEventHandler
:De l'approche:
est raisonnable, mais (comme pour les autres réponses) il y a un petit risque de les appelants qui pensent qu'ils déconnecté l'obtention de l'événement. Peu probable dans la réalité.
Une autre approche est une méthode d'extension:
Ensuite dans votre classe, vous pouvez simplement utiliser:
OriginalL'auteur Marc Gravell
Si le Thermostat de la classe n'a pas besoin d'être thread-safe alors oui, le code ci-dessus est fine aussi longtemps qu'il n'y a qu'un seul thread accéder à cette instance de Thermostat il n'existe aucun moyen pour OnTemperatureChange à devenir non enregistrées entre le test de la nullité et l'appel à la manifestation.
Si vous avez besoin de faire Thermostat thread-safe, alors vous voudrez peut-être jeter un oeil à l'article suivant (nouveau pour moi, ressemble à une bonne lecture):
http://www.yoda.arachsys.com/csharp/events.html
Pour l'enregistrement, la recommandation est que vous développez vos classes ne pas être thread safe, sauf si la sécurité des threads est explicitement nécessaire, car elle peut augmenter considérablement la complexité de votre code.
OriginalL'auteur Justin
Utiliser un point d'interrogation pour un accès conditionnel:
OnTemperatureChange?.Invoke();
C# 6 a été publié en 2016, vous pouvez simplement mettre à niveau.
Je suis au courant, c'était juste un avertissement. Pas tous les environnements de soutien. (L'unité, par exemple, ne va pas)
OriginalL'auteur Luca Ziegler
Je viens de voir un peu de refactoring qui pourrait être fait, mais sinon ça a l'air bien...
Merci. Cela ne veut pas avoir les mêmes problèmes que les autres à mentionner?
ne serait pas Invoke() de travail? Il est un délégué n'est-ce pas? Ne pas essayer d'être intelligent.. j'ai peut-être raté quelque chose.
Non, je veux dire le problème thread.
Yep, vous êtes dans un catch-22. Si vous le copiez dans une variable temp et faire le chèque pour les nuls, vous pouvez être pris avec le fait que l'auditeur qui annule l'inscription d'eux-mêmes est plus dans un état capable de recevoir l'événement. Un véritable casse-tête que je ne vois pas une bonne réponse.
OriginalL'auteur bytebender