L'expéditeur d'un événement doit-il toujours être un objet générique?

10

Lors de la programmation d'événements en C #, il est conseillé de créer un délégué sous forme de:

delegate XEventHandler(object sender, XEventArgs e);

Ma question porte sur le premier argument du délégué, object sender. Doit-il toujours être générique object? Avoir un expéditeur de type objectentraîne toujours un code similaire à celui-ci.

val = ((ConcreteType)sender).Property;

ou, encore plus verbeux,

ConcreteType obj = sender as ConcreteType
if (obj != null) { ... }

Un argument contre les expéditeurs fortement typés est que d'autres objets peuvent transmettre l'événement sans se soucier du type. Bien que cela puisse avoir un sens dans les environnements GUI, je ne suis pas sûr que cela puisse bénéficier en dehors d'une interface graphique.

Que faire si la classe de l'expéditeur est toujours connue (au moins en tant que classe abstraite)? Par exemple, si j'implémente un ListChangedévénement dans une Listclasse abstraite , et si d'autres classes vont en hériter (par exemple LinkedList, ArrayList), est-il correct de définir mon délégué avec un expéditeur de type List?

delegate ListChangedEventHander(List sender, ListChangedEventArgs e);

Ou y aurait-il un inconvénient à changer le conventionnel object senderen un type plus spécifique?

sampathsris
la source

Réponses:

10

À ce stade, il s'agit principalement d'une convention (assez forte). Autrement dit, ce sera bizarre si vous écrivez une bibliothèque qui ne respecte pas cette convention.

Les directives de conception d'événements indiquent:

DO utiliser objectle type du premier paramètre du gestionnaire d'événements, et l' appeler sender.

Cependant, vous pouvez noter que les instructions actuelles indiquent que vous ne devez pas définir votre propre délégué personnalisé pour les événements, mais l'utiliser à la EventHandler<T>place, si vous le pouvez.

Quant à la conception, je suppose qu'elle favorise également la réutilisation des gestionnaires d'événements, même dans des contextes non prévus à l'origine par le concepteur d'origine de l'événement.

jhominal
la source
2
Ughhh ... juste parce que Microsoft a décidé de rendre leurs directives suffisamment génériques pour être applicables à tout le monde, cela ne signifie pas que ce soit une bonne idée pour tout le monde de suivre leurs directives. Il est fort probable que "tout le monde" n'écrive pas de code à utiliser par des millions d'autres développeurs. J'ai grincé des dents aux 2/3 des recommandations du lien que vous avez fourni.
Dunk
Pour vous dire la vérité, cette "directive" ressemble plus ou moins à la notation hongroise de l'API Windows. Quelqu'un de brillant a commencé pour une très bonne raison, puis tout le monde a commencé à en abuser. Quand il y a une directive, il vaut mieux avoir une bonne raison derrière cette directive. Et ce que je pense que la raison de cette directive est que l' System.Windows.Formsespace de noms est l'endroit où les événements sont les plus utilisés, et il était logique de souscrire à l' Clickévénement de Buttonou a CheckBox. L'expéditeur doit donc être générique. ...
sampathsris
... Mais en ce qui concerne les autres domaines de fonctionnalité contenus, plus spécifiques, l'expéditeur peut ne pas être une classe générique. Voir à nouveau mon exemple d'une hiérarchie de classes de Lists.
sampathsris du
11
@Dunk: Et c'est le point. Cette ligne directrice provient de Framework Design Guidelines, qui concerne principalement le code consommé par d'autres . Non pas parce que c'est la meilleure solution, mais parce que c'est la moins surprenante. C'est la meilleure option pour un framework . Pour les petites bibliothèques, si le cas d'utilisation est bien spécifié, moins de conseils sont applicables. Microsoft le dit explicitement au début du livre.
Magus
1
Je ne discute pas avec la réponse, je l'ai même votée parce qu'elle provient d'une source fiable. Je dis simplement que je n'utiliserais pas les lignes directrices. Si un événement est censé envoyer des données spécifiques, je n'enverrai que les données spécifiques. De plus, la fonction d'événement fonctionne très bien si vous les utilisez comme ils étaient destinés à être utilisés.
Dunk
0

La raison de la recommandation est qu'elle permet des modifications futures qui ne nécessitent pas nécessairement des modifications du code existant, et en particulier de l'interface publique.

Le mécanisme d'événement lui-même peut toujours être utilisé pour les événements de style "VB6", mais vous devrez changer tous les consommateurs existants si vous avez besoin de changer la signature (ou pire: créer de nouvelles versions des mêmes événements). Avec l'approche recommandée, tant que les éléments les plus récents héritent des éléments existants, vous pouvez mettre à jour la signature sans corriger le code existant.

Mark Hurd
la source