174 votes

événement Action <>vs event EventHandler <>

Est-il différent entre déclarant event Action<> et event EventHandler<>.

En supposant qu'il n'a pas d'importance ce que l'objet fait a soulevé un événement.

par exemple:

public event Action<bool, int, Blah> DiagnosticsEvent;

vs

public event EventHandler<DiagnosticsArgs> DiagnosticsEvent;

class DiagnosticsArgs : EventArgs
{
    public DiagnosticsArgs(bool b, int i, Blah bl)
    {...}
    ...
}

l'utilisation serait presque la même dans les deux cas:

obj.DiagnosticsEvent += HandleDiagnosticsEvent;

Il y a plusieurs choses que je n'aime pas à propos de event EventHandler<> modèle:

  • Supplémentaire de déclaration de type dérivé de EventArgs
  • Passage obligatoire de la source de l'objet – souvent personne ne se soucie

Plus de code, plus de code à maintenir, sans aucun avantage clair.

En conséquence, je préfère event Action<>

Toutefois, uniquement si il y a trop d'arguments de type en Action<>, puis une classe supplémentaire serait nécessaire.

106voto

Paul Rohde Points 701

En fonction des réponses précédentes, je vais casser ma réponse en trois zones.

D'abord, les limites physiques de l'aide d' Action<T1, T2, T2... > vs à l'aide d'une classe dérivée de l' EventArgs. Il en existe trois: tout d'Abord, si vous modifiez le nombre ou les types de paramètres, chaque méthode qui s'abonne à devront être modifiés pour les rendre conformes au nouveau modèle. Si c'est face au public, événement que la 3e partie des assemblées utiliser, et il n'y a aucune possibilité que l'événement args allait changer, ce serait une raison pour utiliser une classe dérivée de l'événement args pour la cohérence de saké (n'oubliez pas, vous pouvez toujours utiliser un Action<MyCustomClass>) en Second lieu, à l'aide de Action<T1, T2, T2... > vous empêcherait de passer de RETOUR à l'appel de la méthode, sauf si vous avez un certain type de l'objet (avec une manche de la propriété par exemple) qui est transmis en même temps que l'Action. Troisièmement, vous n'obtenez pas les paramètres nommés, donc si vous êtes de passage 3 bool's un int, deux strings', et un DateTime, vous n'avez aucune idée de ce que le sens de ces valeurs. Comme une note de côté, vous pouvez toujours avoir un "Feu de cet événement en toute sécurité de la méthode tout en utilisant Action<T1, T2, T2... >".

Deuxièmement, la cohérence des implications. Si vous avez un grand système, vous travaillez déjà avec, il est presque toujours préférable de suivre la façon dont le reste de l'installation est conçue, sauf si vous avez une très bonne raison de ne pas trop. Si vous avez publiquement face aux événements qui doivent être maintenues, la capacité de remplacer les classes dérivées peuvent être importantes. Gardez cela à l'esprit.

Troisièmement, la vraie vie pratique, personnellement, je trouve que j'ai tendance à créer beaucoup de l'un des événements exceptionnels pour des choses comme des modifications de la propriété que j'ai besoin d'interagir avec (Surtout quand on fait de MVVM avec les modèles de vue qui interagissent les uns avec les autres) ou de l'endroit où l'événement a un seul paramètre. La plupart du temps, ces événements prennent la forme d' public event Action<[classtype], bool> [PropertyName]Changed; ou public event Action SomethingHappened;. Dans ces cas, il y a deux avantages. Tout d'abord, je reçois un type pour la délivrance de la classe. Si MyClass déclare et est la seule classe de tir à l'événement, je reçois explicite d'une instance de MyClass pour travailler avec le gestionnaire d'événement. Deuxièmement, pour de simples événements tels que le changement de propriété d'événements, la signification des paramètres est évident et est indiqué dans le nom du gestionnaire d'événement et je n'ai pas à créer une multitude de classes de ce type d'événements.

75voto

Fredrik Mörk Points 85694

La principale différence est que si vous utilisez Action<> de votre événement à ne pas suivre le modèle de conception de pratiquement n'importe quel événement dans le système, que je considère comme un inconvénient.

L'un à l'envers avec le dominant design pattern (en dehors de la puissance de la similitude), c'est que vous pouvez étendre l' EventArgs objet avec de nouvelles propriétés, sans altérer la signature de l'événement. Ce serait possible si vous avez utilisé Action<SomeClassWithProperties>, mais je ne vois vraiment pas le point avec la non utilisation de l'ordinaire approche dans ce cas.

20voto

Paul Matovich Points 336

L'avantage d'un wordier approche vient lorsque votre code est à l'intérieur d'une ligne de 300 000 du projet.

L'utilisation de l'action, comme vous l'avez, il n'ya aucun moyen de me dire ce que bool, int, et Bla. Si votre action passée à un objet qui a défini les paramètres, puis sur ok.

À l'aide d'un Gestionnaire d'événements qui voulait un EventArgs et si vous voulez compléter votre DiagnosticsArgs exemple avec des getters pour les propriétés qui ont fait des commentaires à leur but, puis vous demande serait plus compréhensible. Aussi, s'il vous plaît commentaire ou entièrement nom de l'argumentation dans la DiagnosticsArgs constructeur.

19voto

Marc Gravell Points 482669

Sur la plus grande partie, je dirais de suivre le modèle. J' ai dévié, mais très rarement, et pour des raisons spécifiques. Dans le cas présent, le plus gros problème que j'avais c'est que je serais probablement toujours utiliser un Action<SomeObjectType>, ce qui me permet d'ajouter d'autres propriétés plus tard, et pour une utilisation occasionnelle 2 voies de la propriété (pensez - Handled, ou d'autres commentaires-événements où l'abonné doit de définir une propriété de l'objet d'événement). Et une fois que vous avez commencé sur cette ligne, vous pourriez aussi bien utiliser EventHandler<T> pour certains T.

6voto

Paul Westcott Points 230

Si vous suivez l'événement standard modèle, vous pouvez ajouter une extension de la méthode pour faire la vérification de l'événement de tir plus sûr et plus facilement. (c'est à dire le code suivant ajoute une extension de la méthode appelée SafeFire() qui ne prend la valeur null est à vérifier, ainsi que (évidemment) la copie de l'événement dans une variable distincte pour être sûr de l'habituel null course-condition qui peut affecter les événements.)

(Même si je suis en nature de deux esprits si vous devriez être à l'aide de méthodes d'extension sur des objets nuls...)

public static class EventFirer
{
    public static void SafeFire<TEventArgs>(this EventHandler<TEventArgs> theEvent, object obj, TEventArgs theEventArgs)
        where TEventArgs : EventArgs
    {
        if (theEvent != null)
            theEvent(obj, theEventArgs);
    }
}

class MyEventArgs : EventArgs
{
    // Blah, blah, blah...
}

class UseSafeEventFirer
{
    event EventHandler<MyEventArgs> MyEvent;

    void DemoSafeFire()
    {
        MyEvent.SafeFire(this, new MyEventArgs());
    }

    static void Main(string[] args)
    {
        var x = new UseSafeEventFirer();

        Console.WriteLine("Null:");
        x.DemoSafeFire();

        Console.WriteLine();

        x.MyEvent += delegate { Console.WriteLine("Hello, World!"); };
        Console.WriteLine("Not null:");
        x.DemoSafeFire();
    }
}

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