Manière préférée de déclarer des événements

14

Je suis assez satisfait de ma compréhension du modèle d'événement .NET. Je pense que je peux mal comprendre une petite nuance du système.

Quand j'ai commencé à mettre des événements dans mes classes, j'utilisais la méthode standard comme ceci:

public event EventHandler<MyEventArgs> MyEvent;

Cela signifiait que tout abonnement à l'événement aurait besoin d'une méthode comme:

void HandleThatEvent(object sender, MyEventArgs args){...}

Ce qui est bien, mais j'ai trouvé que je me soucierais rarement de l'expéditeur, donc cela faisait gonfler beaucoup de signatures de méthode.

Je suis donc passé à déclarer mes propres types de délégués

public delegate void MyEventHandler(SomeClass argument);

Ce qui a réduit l'encombrement, mais m'a laissé un petit problème en ce qui concerne l'écriture des gestionnaires:

eventImplmentor.MyEvent += HandleThatEvent;
.
.
.
void HandleThatEvent(/*oh, um, what arguments does it take? Intellisense isn't telling me*/)

Je devrais donc revenir à la déclaration du délégué et regarder, puis revenir en arrière et les écrire, ou le compiler et attendre d'être informé.

Alors maintenant , à la place, je suis juste en utilisant Action, Action<T>ou ce qui convient modèle.

public event Action<SomeClass> MyEvent;

Pour que je puisse survoler l'événement et être informé des paramètres qu'il attend.

Ma question, après tout cela: existe-t-il une meilleure pratique pour déclarer des événements en C #? Dois-je revenir en arrière EventHandler<T>ou est-ce Action<T>acceptable?

Matt Ellen
la source
N'oubliez pas de vous assurer que le gestionnaire est copié localement à l'endroit où vous déclenchez l'événement, toujours vouloir le faire pour la sécurité des threads.
Snoop
Vous pouvez écrire vos propres événements de type sécurisé intelligents, moyens et maigres dans du code encapsulé, mais tout ce que vous publiez doit suivre le modèle standard ou cela ne fera que confondre les utilisateurs de votre classe (et apparemment certains outils aussi).
Martin Maat

Réponses:

8

Pour une gestion simple et interne des événements, il y a ceux qui utilisent simplement Actionou Action<T>, comme vous le proposez. J'ai tendance à utiliser le modèle standard, y compris l'expéditeur, même pour les événements internes, car vous ne savez jamais quand vous voudrez plus tard exposer une classe ou un événement, et je ne voudrais pas la pénalité d'avoir à refactoriser la méthode d'événement juste pour faire il public.

Je suis d'accord avec vous que la signature de gestion des événements est un peu plus lourde qu'elle ne devrait l'être pour des scénarios simples, mais elle est bien conçue pour gérer la migration incrémentielle car des arguments d'événement supplémentaires pourraient devenir nécessaires au fil du temps. Dans l'ensemble, je m'en tiendrai au modèle standard, d'autant plus que, comme vous l'avez remarqué, vous n'obtiendrez un support IntelliSense approprié que si vous le faites.

Pour ce que ça vaut, j'ai consacré du temps à cela et j'ai proposé un modèle de gestion des événements différent: Signature d'événement dans .NET - Utilisation d'un «expéditeur» typé fort? . Le but ici n'était pas de supprimer l'expéditeur, mais de le rendre typiquement fort comme TSenderau lieu de faiblement typé comme System.Object. Il fonctionne très bien; cependant, on perd le support IntelliSense lorsque vous faites cela, il y a donc un compromis malheureux.

Dans l'ensemble, je m'en tiendrai au modèle standard, mais il est intéressant de penser à de meilleures façons de le faire.

Mike Rosenblum
la source
Merci de m'avoir indiqué votre question SO. C'est très intéressant. Je ne comprends toujours pas pourquoi il est si important que l'expéditeur soit obligatoire. La plupart du temps, je m'en fiche de l'expéditeur. S'agit-il simplement d'une règle arbitraire de la SEP?
Matt Ellen
Non, bien sûr, vous pouvez déclarer vos délégués comme bon vous semble. C'est la politique .NET de toujours inclure l'expéditeur, et ce n'est pas tout à fait une mauvaise idée.
Neil
@Neil: Je comprends que cela soit utile parfois, mais je n'ai pas la politique de toujours le faire - d'autant plus que MS recommande de faire les événements à sa manière. L'une des choses que j'aime beaucoup dans les événements est la possibilité de découpler les classes. Si j'inclus l'objet, il est à nouveau couplé. Si c'est juste une question de conformité CLS, je peux vivre avec ça.
Matt Ellen
Il est couplé à nouveau uniquement si vous utilisez l'objet expéditeur, sinon peu importe ce qui est mis comme valeur d'expéditeur puisque vous ne l'utilisez pas. La dépendance n'existe que si vous avez besoin d'une dépendance. Je vois d'où tu viens, et si l'expéditeur d'objet disparaissait de tout le code de n'importe quel serveur de la planète, je ne resterais pas debout la nuit.
Neil
Oui, vous pouvez envoyer 'null' en tant qu'expéditeur si vous le voulez vraiment ... Mais, en incluant l'expéditeur, le gestionnaire d'événements lui-même pourrait se désinscrire s'il le voulait. Dans l'ensemble, cependant, je dirais que connaître la source de l'événement est généralement assez important.
Mike Rosenblum