.NET Eventhandler - Generic oder nein?
Frage
Jedes Mal, wenn ich in tief in einem C # -Projekt zu starten, habe ich am Ende mit vielen Veranstaltungen auf, die wirklich nur ein einzelnes Element übergeben müssen. Ich bleibe mit der EventHandler
/ EventArgs
Praxis, aber was Ich mag zu tun habe so etwas wie:
public delegate void EventHandler<T>(object src, EventArgs<T> args);
public class EventArgs<T>: EventArgs {
private T item;
public EventArgs(T item) {
this.item = item;
}
public T Item {
get { return item; }
}
}
Später kann ich meine haben
public event EventHandler<Foo> FooChanged;
public event EventHandler<Bar> BarChanged;
Allerdings scheint es, dass der Standard für .NET ist eine neue Delegierte und EventArgs
Unterklasse für jede Art von Veranstaltung zu erstellen. Gibt es etwas falsch mit meinem generischen Ansatz?
EDIT: Der Grund für diesen Beitrag ist, dass ich nur diese in einem neuen Projekt neu erstellt, und sicherstellen wollte, dass es war ok. Eigentlich war ich neu erstellt, wie ich geschrieben. Ich fand, dass es eine allgemeine
EventHandler<TEventArgs>
ist, so dass Sie die generischen Delegaten nicht erstellen müssen, aber Sie müssen noch die allgemeine EventArgs<T>
Klasse, weil TEventArgs: EventArgs
.
Ein weiterer EDIT: Ein Nachteil (für mich) der integrierte Lösung ist die zusätzliche Ausführlichkeit:
public event EventHandler<EventArgs<Foo>> FooChanged;
vs.
public event EventHandler<Foo> FooChanged;
Es kann ein Schmerz für die Kunden allerdings für Ihre Events zu registrieren, da die Namespace System standardmäßig importiert wird, so müssen sie manuell Ihren Namensraum suchen, auch mit einem schicken Tool wie ReSharper ... Wer irgendwelche Ideen in Bezug auf das?
Lösung
Delegierter der folgenden Form ist seit dem .NET Framework 2.0 hinzugefügt
public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs
Sie nähern sich geht ein bisschen weiter, da Sie für EventArgs mit Artikel Einzel Daten out-of-the-Box-Implementierung zur Verfügung stellen, aber es fehlt mehrere Eigenschaften der ursprünglichen Idee:
- Sie können nicht mehr Eigenschaften zu den Ereignisdaten hinzuzufügen, ohne abhängig Code zu ändern. Sie werden die Delegierten Signatur ändern müssen, um mehr Daten zu dem Ereignis Teilnehmer zur Verfügung zu stellen.
- Ihr Datenobjekt generisch ist, aber es ist auch „anonymous“, und während Sie den Code lesen müssen Sie das „Item“ Eigentum von Verwendungen zu entziffern. Es soll es sieht nach dem Datum genannt werden.
- die Verwendung von Generika diese Weise können Sie nicht parallel Hierarchie von EventArgs machen können, wenn Sie Hierarchie der zugrunde liegenden (item) Typen. Z.B. EventArgs
ist nicht Basistyp für EventArgs , auch wenn Basetype Basis für DerivedType ist.
Also, ich denke, es ist besser, generische Eventhandler
Andere Tipps
Um generische Ereignisdeklaration zu erleichtern, habe ich ein paar Code-Schnipsel für sie. Um sie zu verwenden:
- Kopieren Sie den gesamten Code-Schnipsel.
- Fügen Sie ihn in eine Textdatei (beispielsweise im Editor).
- Speichern Sie die Datei mit einer .snippet Erweiterung.
- Legen Sie die .snippet Datei in Ihrem entsprechenden Code-Schnipsel-Verzeichnis, wie zum Beispiel:
Visual Studio 2008 \ Code Snippets \ Visual C # \ My Code Snippets
Hier ist eine, die eine benutzerdefinierte EventArgs-Klasse mit einer Eigenschaft verwendet:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Generic event with one type/argument.</Title>
<Shortcut>ev1Generic</Shortcut>
<Description>Code snippet for event handler and On method</Description>
<Author>Kyralessa</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Type of the property in the EventArgs subclass.</ToolTip>
<Default>propertyType</Default>
</Literal>
<Literal>
<ID>argName</ID>
<ToolTip>Name of the argument in the EventArgs subclass constructor.</ToolTip>
<Default>propertyName</Default>
</Literal>
<Literal>
<ID>propertyName</ID>
<ToolTip>Name of the property in the EventArgs subclass.</ToolTip>
<Default>PropertyName</Default>
</Literal>
<Literal>
<ID>eventName</ID>
<ToolTip>Name of the event</ToolTip>
<Default>NameOfEvent</Default>
</Literal>
</Declarations>
<Code Language="CSharp"><![CDATA[public class $eventName$EventArgs : System.EventArgs
{
public $eventName$EventArgs($type$ $argName$)
{
this.$propertyName$ = $argName$;
}
public $type$ $propertyName$ { get; private set; }
}
public event EventHandler<$eventName$EventArgs> $eventName$;
protected virtual void On$eventName$($eventName$EventArgs e)
{
var handler = $eventName$;
if (handler != null)
handler(this, e);
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Und hier ist eine, die zwei Eigenschaften hat:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Generic event with two types/arguments.</Title>
<Shortcut>ev2Generic</Shortcut>
<Description>Code snippet for event handler and On method</Description>
<Author>Kyralessa</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type1</ID>
<ToolTip>Type of the first property in the EventArgs subclass.</ToolTip>
<Default>propertyType1</Default>
</Literal>
<Literal>
<ID>arg1Name</ID>
<ToolTip>Name of the first argument in the EventArgs subclass constructor.</ToolTip>
<Default>property1Name</Default>
</Literal>
<Literal>
<ID>property1Name</ID>
<ToolTip>Name of the first property in the EventArgs subclass.</ToolTip>
<Default>Property1Name</Default>
</Literal>
<Literal>
<ID>type2</ID>
<ToolTip>Type of the second property in the EventArgs subclass.</ToolTip>
<Default>propertyType1</Default>
</Literal>
<Literal>
<ID>arg2Name</ID>
<ToolTip>Name of the second argument in the EventArgs subclass constructor.</ToolTip>
<Default>property1Name</Default>
</Literal>
<Literal>
<ID>property2Name</ID>
<ToolTip>Name of the second property in the EventArgs subclass.</ToolTip>
<Default>Property2Name</Default>
</Literal>
<Literal>
<ID>eventName</ID>
<ToolTip>Name of the event</ToolTip>
<Default>NameOfEvent</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[public class $eventName$EventArgs : System.EventArgs
{
public $eventName$EventArgs($type1$ $arg1Name$, $type2$ $arg2Name$)
{
this.$property1Name$ = $arg1Name$;
this.$property2Name$ = $arg2Name$;
}
public $type1$ $property1Name$ { get; private set; }
public $type2$ $property2Name$ { get; private set; }
}
public event EventHandler<$eventName$EventArgs> $eventName$;
protected virtual void On$eventName$($eventName$EventArgs e)
{
var handler = $eventName$;
if (handler != null)
handler(this, e);
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Sie können das Muster folgen ihnen mit so vielen Eigenschaften zu erstellen, wie Sie möchten.
Nein, ich glaube nicht, das der falsche Ansatz ist. Ich denke, es ist sogar in der [fantastisch] Buch Framework Design Guidelines empfohlen. Ich tue das gleiche.
Dies ist die richtige Umsetzung. Es hat sich auf das .NET Framework (mscorlib) hinzugefügt worden, da Generika erste verfügbare kam (2,0).
Weitere Informationen über seine Verwendung und Implementierung finden Sie im MSDN: http: // msdn .microsoft.com / en-us / library / db0etb8x.aspx
Das erste Mal, dass ich dieses kleine Muster sah, war ich mit Composite-UI-Anwendungsblock von MS Patterns & Practices-Gruppe.
Es wird keine rote Fahne auf mich werfen; in der Tat ist es auch eine intelligente Art und Weise Generika nutzt die DRY Regel zu folgen.
Da .NET 2.0
EventHandler<T>
implementiert.
Sie können generische Eventhandler auf MSDN finden http://msdn.microsoft. com / en-us / library / db0etb8x.aspx
Ich habe mit generischen Eventhandler ausgiebig und war in der Lage, so genannte zu verhindern „Explosion der Typen (Klassen)“ Das Projekt wurde kleiner gehalten und leichter zu navigieren.
Kommen Sie mit einem neuen, intuitiven Delegierten mich für nicht-generische Eventhandler Delegaten ist schmerzhaft und überschneiden sich mit dem bestehenden Typen Anfügen „* Eventhandler“ neuer Delegierter Name hilft nicht viel meiner Meinung nach
Ich glaube, dass die jüngsten Versionen von .NET haben nur so ein Event-Handler in ihnen definiert. Das ist ein großer Daumen nach oben, so weit es mich betrifft.
/ EDIT
Haben Sie nicht die Unterscheidung bekommen es ursprünglich. Solange Sie eine Klasse, die von EventArgs erbt sind vorbei zurück, die du bist, ich sehe kein Problem. Ich wäre besorgt, wenn Sie nicht die resultfor Wartbarkeit Gründe Einwickeln wurden. Ich sage immer noch sieht es gut aus für mich.
generic Ereignishandler Instanzen verwenden
Vor dem .NET Framework 2.0, um benutzerdefinierte Informationen an den Ereignishandler zu passieren, mußte ein neuer Delegierter erklärt wird, dass eine Klasse angegeben, abgeleitet von der System.EventArgs Klasse. Das ist nicht mehr wahr in .NET
Framework 2.0, die die System.EventHandler