Verfügt .NET über ein integriertes EventArgs <T>?


84

Ich bereite mich darauf vor, eine generische EventArgs-Klasse für Ereignisargumente zu erstellen, die ein einziges Argument enthalten:

public class EventArg<T> : EventArgs
{
    // Property variable
    private readonly T p_EventData;

    // Constructor
    public EventArg(T data)
    {
        p_EventData = data;
    }

    // Property for EventArgs argument
    public T Data
    {
        get { return p_EventData; }
    }
}

Hat C # zuvor dieselbe Funktion in die Sprache integriert? Ich erinnere mich an so etwas, als C # 2.0 herauskam, aber jetzt kann ich es nicht finden.

Oder anders ausgedrückt: Muss ich meine eigene generische EventArgs-Klasse erstellen oder stellt C # eine bereit? Danke für Ihre Hilfe.


9
Sie haben vielleicht gesehenEventhandler<T>
Henk Holterman

1
Möglicherweise haben Sie EventArgs<T>CAB / SCSF-basierten Code gesehen. Dies ist in CAB / SCSF-Anwendungen durchaus üblich. Obwohl es nicht Teil des Frameworks ist, gibt es eine EventArgs <T> -Implementierung.
Shaun Wilson

Antworten:


66

Nein. Sie haben wahrscheinlich darüber nachgedacht EventHandler<T>, wie Sie den Delegaten für einen bestimmten Typ von EventArgs definieren können.

Ich persönlich finde das allerdings nicht EventArgs<T>ganz so gut. Die Informationen, die als "Nutzlast" in den Ereignisargumenten verwendet werden, sollten meiner Meinung nach eine benutzerdefinierte Klasse sein, um die Verwendung und die erwarteten Eigenschaften sehr deutlich zu machen. Die Verwendung einer generischen Klasse verhindert, dass Sie aussagekräftige Namen einfügen können. (Was bedeutet "Daten"?)


49
In datenzentrierten, MPI-ähnlichen Anwendungen ist es durchaus üblich, dass EventArgs <T> für die Datenverarbeitung vorhanden ist, damit Entwickler ein integriertes, typsicheres Abonnement- / Registrierungssystem (.NET Events and Delegates) nutzen können. da es absolut keinen Sinn macht, EventArgs-Unterklassen nur zum Transport von Daten zu erstellen. Wenn Sie Daten transportieren möchten, ist es wahrscheinlich sinnvoller, ein EventArgs <T> zu definieren, das Sie für diskrete Verwendungen UNTER Berücksichtigung der zu transportierenden Daten unterordnen können. TL: DR Dieser erste Teil dieser Antwort ist sachlich und genau, der zweite Teil ist subjektiv / Meinung.
Shaun Wilson

1
Ich nehme an, Sie haben Recht ... widerstehen Sie der Faulheit, die mich hierher gebracht hat. Es ist wie wenn faule Entwickler Tuple <,> verwenden. Schreckliches Zeug.
CRice

Ein guter Punkt, aber dies würde im Wesentlichen dasselbe tun wie Microsoft, als sie die Tag-Eigenschaft zu den Controls-Klassen hinzufügten. Natürlich, nur weil MS es getan hat, macht es nicht richtig.
Ken Richards

1
Ich stimme dem ersten Kommentator zu, die gesamte zweite Hälfte dieser Antwort ist eine subjektive Meinung / Code-Religion, die nicht konstruktiv war. :(
BrainSlugs83

5
Wie übermittelt EventHandler <Kunde> oder EventHandler <Bestellung> weniger Informationen als CustomerEventHandler oder OrderEventHandler ?
Quarkly

33

Ich muss sagen, ich verstehe hier nicht alle Puristen. dh wenn Sie bereits eine Taschenklasse definiert haben - die alle Besonderheiten, Eigenschaften usw. enthält - warum erstellt der Hack eine zusätzliche unnötige Klasse, um dem Ereignis- / Argumentmechanismus, dem Signaturstil, folgen zu können? Die Sache ist - nicht alles, was in .NET vorhanden ist - oder was in dieser Angelegenheit "fehlt" - ist "gut" - MS "korrigiert" sich seit Jahren selbst ... Ich würde sagen, gehen Sie einfach und erstellen Sie eine - wie ich - weil ich es einfach so brauchte - und mir viel Zeit gespart habe,


3
In diesem Fall geht es den Puristen darum, die Absicht so klar wie möglich zu machen. In einer Produktions-App habe ich Dutzende dieser EventArgs-Klassen. In einem Jahr wird es einfacher zu verstehen sein, was ich getan habe, wenn ich Reeds Rat befolge und eine benutzerdefinierte EventArgs-Klasse erstelle.
David Veeneman

9
wollte niemanden beschriften :) Punkt ist in der "generischen" in der Veranstaltung - wenn Sie nur ein Dutzend verschiedene Ereignisse benötigen, ok. Aber wenn Sie die Natur des T vorher nicht kennen - das ist nur zur Laufzeit bekannt -, brauchen Sie ein generisches Ereignis. Wenn Sie also eine App haben, die sich gut mit Generika befasst, eine beliebige Anzahl von Typen, die unbekannt sind, dann benötigen Sie auch generische Ereignisse. oder dh es gibt keine klare Lösung für jedes Problem, Faustregel ist nur Faustregel - und das habe ich mit Puristen gemeint, jede Lösung ist anders, man muss die Dinge, Vor- und Nachteile
abwägen

2
Design ist nicht schwarz und weiß, daher stimme ich NSGaga hier eher zu. Manchmal ist "schnell und schmutzig" angebracht. Die Sprache sollte für die meisten Anwendungsfälle funktionsreich sein. Es sollte Sache des Entwicklers sein, zu entscheiden, was angemessen ist. Das letzte Mal, als MS versuchte, "gutes" Design durch Einschränkung der Sprache zu erzwingen, war WPF, als sie versuchten, die Verwendung von XAML durch schwerwiegende Beeinträchtigung der .NET-API zu erzwingen, und es war schrecklich.
Robear

9

Es existiert. Zumindest jetzt.

Sie finden sie DataEventArgs<TData>in verschiedenen Microsoft-Assemblys / Namespaces, z. B. Microsoft.Practices.Prism.Events . Dies sind jedoch Namespaces, die Sie möglicherweise nicht als natürlich in Ihr Projekt aufnehmen können, sodass Sie möglicherweise nur Ihre eigene Implementierung verwenden.


Ich habe versucht, Empfehlungen und Überlegungen zu finden, wann und warum eine solche generische EventArgs-Klasse verwendet werden soll. Siehe auch: stackoverflow.com/questions/15766219/…
Ulf Åkerstedt

Hier sind einige Aspekte, die Sie beachten sollten,
Ulf Åkerstedt

7

Falls Sie sich dafür entscheiden, Prism nicht zu verwenden , aber dennoch einen generischen EventArgs- Ansatz ausprobieren möchten .

public class GenericEventArgs<T> : EventArgs
{
    public T EventData { get; private set; }

    public GenericEventArgs(T EventData)
    {
        this.EventData = EventData;
    }
}

// Verwenden Sie den folgenden Beispielcode, um das ObjAdded- Ereignis zu deklarieren

public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;

// Verwenden Sie den folgenden Beispielcode, um das ObjAdded- Ereignis auszulösen

private void OnObjAdded(TargetObjType TargetObj)
{
    if (ObjAdded!= null)
    {
        ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
    }
}

// Und schließlich können Sie Ihr ObjAdded- Ereignis abonnieren

SubscriberObj.ObjAdded +=  (object sender, GenericEventArgs<TargetObjType> e) =>
{
    // Here you can explore your e.EventData properties
};

3

ES GIBT KEINE EINGEBAUTEN GENERISCHEN ARGS. Wenn Sie dem Microsoft EventHandler-Muster folgen, implementieren Sie Ihre abgeleiteten EventArgs wie vorgeschlagen : public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.

JEDOCH - wenn Ihr Team-Styleguide eine Vereinfachung akzeptiert - kann Ihr Projekt leichtgewichtige Ereignisse wie das folgende verwenden:

public event Action<object, string> MyStringChanged;

Verwendung :

// How to rise
private void OnMyStringChanged(string e)
{
    Action<object, string> handler = MyStringChanged;    // thread safeness
    if (handler != null)
    {
        handler(this, e);
    }
}

// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);

Normalerweise verwenden PoC-Projekte den letzteren Ansatz. Beachten Sie bei professionellen Anwendungen jedoch die FX Cop-Begründung # CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx


1

Das Problem mit einem generischen Typ besteht darin, dass EventArgs (DerivedType) selbst dann nicht von EventArgs (BaseType) erben würde, wenn DerivedType von BaseType erbt. Die Verwendung von EventArgs (BaseType) würde daher die spätere Verwendung einer abgeleiteten Version des Typs verhindern.


2
Dies ist offensichtlich falsch. Bitte sehen Sie "Kovarianz und Kontravarianz in Generika - Microsoft.com" msdn.microsoft.com/en-us/library/dd799517.aspx
Shaun Wilson

1
@ShaunWilson: Welcher Aspekt ist falsch? Man könnte eine kovariante Schnittstelle definieren IEventArgs, aber die einzigen Klassen, die in Bezug auf generische Typparameter generisch sein können, sind Delegaten, denen nicht zugeführt wird Delegate.Combine. Delegaten, die mit verwendet werden, Delegate.Combinesollten nicht kovariant sein, da man z. B. ein Action<DerivedType>in einem Feld vom Typ speichern kann Action<BaseType>, aber ein späterer Versuch Combine, dies mit einer Instanz von zu Action<BaseType>tun, schlägt fehl.
Supercat

-4

Der Grund, warum dies nicht existiert, ist, dass Sie dies implementieren würden. Wenn Sie dann das T ausfüllen, sollten Sie eine Klasse mit stark typisierten eindeutigen Eigenschaften erstellen, die als Datentasche für Ihr Ereignisargument fungiert Nach der Hälfte der Implementierung stellen Sie fest, dass es keinen Grund gibt, diese Klasse nicht einfach von EventArgs zu erben und sie als gut zu bezeichnen.

Es sei denn, Sie möchten nur eine Zeichenfolge oder etwas ähnlich Grundlegendes für Ihre Datentasche. In diesem Fall gibt es wahrscheinlich EventArgs-Klassen in .NET, die für jeden einfachen Zweck gedacht sind, den Sie erreichen.


-1. Ich habe jetzt genau diese Situation, und meine Nutzlast wäre ein unveränderliches Objekt, das eine "Nachricht" ist, die von einem Bus kommt ... und auch an anderen Orten ausgegeben wird. Das benutzerdefinierte EventArgs .... erstellt hier eine redundante Klasse. Ungewöhnlich, aber die Anwendung ist so.
TomTom
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.