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?

War es hilfreich?

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:

  1. 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.
  2. 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.
  3. 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 , verwenden, aber immer noch benutzerdefinierte EventArgs Klassen, organisiert nach den Anforderungen des Datenmodells. Mit Visual Studio und Erweiterungen wie ReSharper, ist es nur eine Frage von wenigen Befehlen neue Klasse zu erstellen, wie die.

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 ) Delegierten eingeführt. Dieser generische Delegaten erlaubt jede Klasse von EventArgs abgeleitet mit dem Event-Handler verwendet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top