74 votes

Dans un gestionnaire d'événements C #, pourquoi le paramètre "sender" doit-il être un objet?

Selon http://msdn.microsoft.com/en-us/library/h0eyck3s(SV.71).aspx le paramètre sender en C# gestionnaire d'événement "est toujours de type objet, même s'il est possible d'utiliser un type spécifique."

Cela conduit à beaucoup de code de gestion des événements comme:-

RepeaterItem item = sender as RepeaterItem
if (item != null) { /* Do some stuff */ }

Maintenant, dans mon cas, je travaille avec le custom C# d'événements (plutôt que l'ASP.NET événements, pas de ASP.NET à toutes les personnes impliquées à ce jour), donc je certainement ne pas avoir à s'inquiéter accidentellement l'exécution d'une opération sur un GridView en-Tête.

Cela dit, pourquoi la convention conseiller contre le fait de déclarer un gestionnaire d'événements avec un plus spécifique? :-

MyType
{
  public event MyEventHander MyEvent;
}

...

delegate void MyEventHander ( MyType sender, MyEventArgs e );

Ai-je raté une chasse aux sorcières?

Modifier

Juste essayer quelque chose pour la taille, il me semble que vous pourriez développer EventHandler<TArgs> avec:-

public class EventArgs<TContent> : EventArgs
{
  public TContent Content { get; set; }
}

public delegate void EventHandler<TContent>
  ( object sender, EventArgs<TContent> e );

N'a que le look qui puent?

Edit 2

Avant que j'accepte une réponse, je dois dire que pour la postérité que je suis d'accord avec le sentiment général dans les réponses de la convention est d'utiliser l'objet, même lorsqu'il est possible d'utiliser un type spécifique, et dans le vrai monde de la programmation, il est important de respecter la convention.

Merci pour vos réponses!

39voto

Jon Skeet Points 692016

Eh bien, c'est un modèle plutôt que d'une règle. Cela signifie qu'un composant peut avancer sur un événement de l'autre, en gardant l'original de l'expéditeur, même si ce n'est pas normal type de collecte de l'événement.

Je suis d'accord c'est un peu étrange, mais c'est probablement la peine de coller à la convention seulement pour la connaissance de l'amour. (La connaissance pour les autres développeurs, ce qui est.) Je n'ai jamais été particulièrement vif sur l' EventArgs moi-même (étant donné que sur son propre, il transmet aucune information), mais c'est un autre sujet. (Au moins, nous avons de l' EventHandler<TEventArgs> maintenant - bien que si il y avait aussi un EventArgs<TContent> pour la commune de situation où vous avez juste besoin d'une seule valeur pour être propagées.)

EDIT: Il est le délégué plus générale, le but, bien sûr - un seul type de délégué peut être réutilisé dans de multiples événements. Je ne suis pas sûr d'acheter que de plus en plus de bonnes raisons - notamment à la lumière des génériques, mais je suppose que c'est quelque chose...

17voto

Keith Points 46288

Je pense qu'il y a une bonne raison à cette convention.

Prenons (et développer) @erikkallen de l'exemple:

void SomethingChanged(object sender, EventArgs e) {
    EnableControls();
}
...
MyRadioButton.Click += SomethingChanged;
MyCheckbox.Click += SomethingChanged;
MyDropDown.SelectionChanged += SomethingChanged;
...

C'est possible (et l'a été depuis .Net 1, avant de génériques) parce que la covariance est pris en charge.

Votre question est tout à fait logique, si vous allez de haut en bas- c'est à dire que vous devez l'événement dans votre code, si vous l'ajoutez à votre contrôle.

Toutefois, la convention est de faciliter la tâche lors de l'écriture de composants dans la première place. Vous savez que, pour tout événement le modèle de base (object sender, EventArgs e) travaillera.

Lorsque vous ajoutez le cas où vous ne savez pas comment il va être utilisé, et vous ne voulez pas arbitrairement contraindre les développeurs à l'aide de votre composant.

Votre exemple d'un générique, fortement typé événement est de bon sens dans votre code, mais ne rentre pas avec d'autres composants écrits par d'autres développeurs. Par exemple, si ils veulent utiliser votre composante avec celles ci-dessus:

//this won't work
GallowayClass.Changed += SomethingChanged;

Dans cet exemple, le type supplémentaire-contrainte est juste de la création de la douleur pour la télécommande développeur. Ils ont maintenant de créer un nouveau délégué juste pour votre composant. Si ils sont en utilisant une charge de vos composants dont ils pourraient avoir besoin d'un délégué pour chacune d'elles.

Je pense que la convention est la peine de suivre pour quoi que ce soit externe ou que vous vous attendez à être utilisé en dehors d'un proche de la nit de l'équipe.

J'aime l'idée du générique de l'événement args - je l'ai déjà utiliser quelque chose de similaire.

11voto

Chris Shouts Points 3542

J'utilise le délégué suivant lorsque je préférerais un expéditeur fortement typé.

 /// <summary>
/// Delegate used to handle events with a strongly-typed sender.
/// </summary>
/// <typeparam name="TSender">The type of the sender.</typeparam>
/// <typeparam name="TArgs">The type of the event arguments.</typeparam>
/// <param name="sender">The control where the event originated.</param>
/// <param name="e">Any event arguments.</param>
public delegate void EventHandler<TSender, TArgs>(TSender sender, TArgs e) where TArgs : EventArgs;
 

Ceci peut être utilisé de la manière suivante:

 public event EventHandler<TypeOfSender, TypeOfEventArguments> CustomEvent;
 

5voto

Marc Gravell Points 482669

Les génériques et l'histoire jouent un grand rôle, surtout avec le nombre de contrôles (etc) qui exposent des événements similaires. Sans les génériques, vous vous retrouvez avec beaucoup d'événements exposer Control, ce qui est largement inutile:

  • vous avez encore de jeter à faire quelque chose d'utile (sauf peut-être une vérification des références, vous pouvez le faire aussi bien avec de la object)
  • vous ne pouvez pas ré-utiliser les événements de non-contrôle

Si l'on considère les génériques, puis de nouveau tout est bien, mais ensuite commencer à entrer dans les questions de l'héritage; si la classe B : A, des événements sur A être EventHandler<A, ...>, et les événements sur B être EventHandler<B, ...>? Encore une fois, très déroutant, difficile pour l'outillage, et un peu brouillon au niveau de la langue.

Jusqu'à ce qu'il y est une meilleure option qui couvre l'ensemble de ces, object travaux; les événements sont presque toujours sur des instances de classe, donc il n'y a pas de boxe etc - juste un plâtre. Et le casting n'est pas très lente.

4voto

erikkallen Points 16601

Je suppose que c'est parce que vous devriez pouvoir faire quelque chose comme

 void SomethingChanged(object sender, EventArgs e) {
    EnableControls();
}
...
MyRadioButton.Click += SomethingChanged;
MyCheckbox.Click += SomethingChanged;
...
 

Pourquoi faites-vous la distribution sécurisée dans votre code? Si vous savez que vous utilisez uniquement la fonction en tant que gestionnaire d'événements pour le répéteur, sachez que l'argument est toujours du type correct et que vous pouvez utiliser un casting de projection, par exemple l'expéditeur (Repeater) au lieu de (l'expéditeur en tant que Repeater).

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