52 votes

Les événements ne sont pas des champs - je ne les comprends pas

En C# en profondeur (un excellent livre à ce jour), Skeet explique les événements ne sont pas des champs. J'ai lu cet article et je ne comprends pas pourquoi la distinction fait une différence.

Je suis un de ces développeurs qui confondent les événements et les instances déléguées. Dans mon esprit, ils sont les mêmes. Ne sont pas seulement une forme d'indirection? Nous pouvons multidiffusion à la fois. Un événement est configuré comme un champ raccourci...bien sûr. Mais, nous sommes en ajoutant ou en supprimant des gestionnaires. Les empiler jusqu'à être appelée lorsque l'événement se déclenche. Ne sommes-nous pas faire la même chose avec les délégués, les empiler et de les appeler appeler?

47voto

Eric Lippert Points 300275

Les autres réponses sont fondamentalement correct, mais voici une autre façon de voir les choses:

Je suis un de ces développeurs qui confondent les événements et les instances déléguées. Dans mon esprit, ils sont les mêmes.

Un vieux dicton de ne pas voir la forêt pour les arbres vient à l'esprit. La distinction que je fais est que les événements sont plus "niveau sémantique" qu'un champ d'instance de délégué. Un événement raconte le consommateur de type "salut, je suis un type qui aime à vous le dire quand quelque chose se passe". Le type de sources d'un événement; cela fait partie de son contrat public.

Comment, en tant qu'un détail d'implémentation, la classe choisit de garder une trace de qui est intéressé dans l'écoute de cet événement, et en quoi et quand à dire que les abonnés que l'événement se passe, c'est l'affaire de la classe. Il arrive d'ordinaire à le faire avec un délégué multicast, mais c'est un détail d'implémentation. C'est une mise en œuvre commune de détails qu'il est raisonnable de confondre les deux, mais nous avons réellement deux choses différentes: d'une surface publique, et d'une salle de détail d'implémentation.

De même, les propriétés de décrire la sémantique d'un objet: un client a un nom, de sorte que le Client de la classe a un Nom de propriété. Vous pourriez dire que "leur nom" est une propriété d'un client, mais vous ne serait jamais dire que "leur nom" est un domaine d'un client; c'est un détail de l'implémentation d'une classe particulière, pas un fait au sujet de l'entreprise de la sémantique. Qu'une propriété est généralement mis en œuvre comme un domaine privé de détail de la classe de la mécanique.

41voto

Ben Voigt Points 151460

Les propriétés ne sont pas les champs, bien qu'ils se sentent comme eux. Ils sont en fait une paire de méthodes (getter et setter) avec une syntaxe spéciale.

Les événements sont de même une paire de méthodes (s'abonner et se désabonner) avec une syntaxe spéciale.

Dans les deux cas, vous avez généralement privé "champ de stockage" à l'intérieur de votre classe, qui contient la valeur manipulée par les getter/setter/s'abonner/se désabonner méthodes. Et il y a une auto-mise en œuvre de la syntaxe pour les deux propriétés et des événements où le compilateur génère le champ de stockage et les méthodes d'accès pour vous.

Le but est également le même: les Propriétés de fournir un accès restreint à un domaine, où une partie de la logique de validation est exécutée avant de stocker une nouvelle valeur. Et un événement fournit un accès limité à un champ de délégué, où les consommateurs ne peuvent s'abonner ou se désabonner, de ne pas lire la liste des abonnés, ni remplacer l'ensemble de la liste à la fois.

24voto

Lasse V. Karlsen Points 148037

Considérons les deux façons de déclarer des événements.

Soit vous déclarez un événement à l'aide d'un explicite add/remove méthode, ou vous déclarer un événement sans de telles méthodes.

En d'autres termes, vous déclarez l'événement comme celui-ci:

public event EventHandlerType EventName
{
    add
    {
        // some code here
    }
    remove
    {
        // some code here
    }
}

ou vous déclarer comme ceci:

public event EventHandlerType EventName;

La chose est, à certains égards, ils sont la même chose, et dans d'autres façons, ils sont complètement différents.

Du point de vue de l'extérieur de code, c'est à ... code de l'extérieur de la classe d'édition de l'événement, ils sont exactement la même chose. Pour vous abonner à un événement, vous appelez une méthode. Pour vous désabonner, vous appelez une méthode différente.

La différence est que dans le deuxième exemple de code ci-dessus, ces méthodes seront fournis par le compilateur pour vous, cependant, c'est encore la façon dont il va être. Pour vous inscrire à l'événement, vous appelez une méthode.

La syntaxe pour le faire, en C#, cependant, est le même, vous n'avez soit:

objectInstance.EventName += ...;

ou:

objectInstance.EventName -= ...;

Donc, à partir du "point de vue externe", les deux voies ne sont pas différents.

Cependant, à l'intérieur de la classe, il y a une différence.

Si vous essayez d'accéder à l' EventNameidentifiant à l'intérieur de la classe, vous êtes en fait en se référant à l' field qui sauvegarde la propriété, mais seulement si vous utilisez la syntaxe qui n'est pas explicitement déclarer add/remove méthode.

Un modèle typique ressemble à ceci:

public event EventHandlerType EventName;

protected void OnEventName()
{
    var evt = EventName;
    if (evt != null)
        evt(this, EventArgs.Empty);
}

Dans ce cas, lorsque vous faites allusion à l' EventName, vous êtes réellement en vous référant à la rubrique qui contient le délégué de type EventHandlerType.

Toutefois, si vous avez déclaré explicitement la add/remove méthodes, en se référant à l' EventName identifiant à l'intérieur de la classe sera comme à l'extérieur de la classe, car le compilateur ne peut pas garantir qu'il connaît le terrain, ou de tout autre mécanisme, dans lequel vous stockez l'abonnement.

9voto

Hans Passant Points 475940

Un événement est un accesseur pour un délégué. Tout comme une propriété est un accesseur pour un champ. Avec exactement le même utilitaire, il empêche le code de déconner avec le délégué de l'objet. Comme une propriété a un accesseur get et set, un événement a l'ajouter et supprimer des accesseur.

Elle ne se comportent un peu différent à partir d'une propriété, si vous n'écrivez pas de l'ajouter et de supprimer des accesseurs vous-même puis le compilateur génère automatiquement. Une salle de sauvegarde de champ qui stocke le délégué de l'objet. Semblable à une automatique à la propriété.

Vous ne faites pas cela souvent, mais ce n'est certainement pas inhabituel. L' .NET framework assez souvent le fait, par exemple, les événements de la Winforms des contrôles sont stockées dans une EventHandlerList et les ajouter/supprimer des accesseurs manipuler cette liste par le biais de son AddHandler() et RemoveHandler() méthodes. Avec l'avantage que tous les événements (ils sont nombreux) ne nécessitent qu'un seul champ dans la classe.

0voto

graumanoz Points 324

Je peux ajouter à l'ancien réponses que les délégués puissent être déclarée à l'intérieur d'un espace de noms de la portée (en dehors de la classe) et les événements peuvent être déclarés uniquement à l'intérieur d'une classe. C'est parce que délégué de classe!

Une autre distinction est que , pour des événements, le contenant de classe est le seul qui peut tirer. Vous pouvez vous abonner/se désabonner via le contenant de la classe, mais ne peut pas le feu (contrairement aux délégués). Alors peut-être vous pouvez comprendre maintenant pourquoi la convention est l'envelopper à l'intérieur d'un protected virtual OnSomething(object sender, EventArgs e). Il est de la descendance pour être en mesure de remplacer la mise en œuvre de la cuisson.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X