2016-07-09 5 views
2

Während ich in VS 2015 herumspielte, erstellte ich eine Eigenschaft und vertippte mich, bevor ich auf Tab traf. Das gab mir eine scheinbar sehr einfache Methode zum Erstellen eines Ereignisses. Ich bin nicht sicher, wie man das annimmt, um zusätzliche Parameter zu akzeptieren, um es Daten zu übergeben (wie ich normalerweise Daten weitergeben möchte, wenn er ein Ereignis mit Informationen darüber, was gerade ausgeführt wird, oder was getan wurde)Einfachste Möglichkeit, Ereignisse in einer Klasse zu erstellen

Der Code gab es als follows:

Auf den ersten Blick ist es ähnlich wie die meisten Beispiele, aber diese Methode scheint keine Delegierten zu erfordern. Vergleichen Sie mit dem folgende Beispiel von How to call an event manually in C#?

public delegate void MyEventHandler(object sender, MyEventArgs e) 
public event MyEventHandler MyEvent; 
public void RaisesMyEvent() 
{ 
    if(MyEvent != null) //required in C# to ensure a handler is attached 
     MyEvent(this, new MyEventArgs(/*any info you want handlers to have*/)); 
} 

Was würde Ich mag wissen, im Lichte des elegantere (clean) Code hat, ist die Methode, die von Microsoft zur Verfügung gestellt (erstes Verfahrens in dieser Frage) besser (es scheint, sauberes), und wenn ja, wie könnte ich es leicht anpassen, um zusätzlich zu Standard-Ereignisargumenten eine Zeichenkette zu akzeptieren und/oder die Ereignisargumente zu erweitern, um Informationen weiterzuleiten?

+2

@VisualVincent Sie brauchen keinen benutzerdefinierten Delegaten, um ein benutzerdefiniertes 'EventArgs' zu verwenden; Zu diesem Zweck gibt es einen generischen 'EventHandler '. –

+0

@ThomasLevesque: Oh, das war mir eigentlich nicht bewusst. Danke, gute Nachricht! –

+0

@ThomasLevesque - könnten Sie ein Beispiel dafür geben. Wenn ich versuche, ein neues Objekt auf der Basis von TEeventArgs zu erstellen, erhalte ich Fehler in meiner Idee, die mich auffordern, eine Eigenschaft mit diesem Namen zu erstellen (es scheint auch nicht zu existieren). –

Antwort

1

Um benutzerdefinierte Argumente auf einem EventHandler passieren, würden Sie Ihre eigene Klasse abgeleitet von EventArgs und ändern Sie die Deklaration wie so erstellen:

public event EventHandler<MyCustomEventArgs> MyEvent; 

Alternativ, wenn Sie nicht mögen object sender in Ihrem Handler mit, Sie tun können:

public event Action<MyCustomEventArgs> MyEvent; 

oder sogar

public event Action<string> MyEvent; 

Soweit die Invokation, Microsoft ist besser. Der Grund dafür ist, dass der von Ihnen geschriebene Null-Check nicht Thread-sicher ist. Das Speichern des Handlers vor der Null-Überprüfung stellt sicher, dass Sie keine Null-Methode aufrufen.

Alternativ verwenden C# 6 Anrufungen und die Vorteile der Null-Konditionaloperator nehmen:

MyEvent?.Invoke(whateverArgs); 
+0

Sehr informativ. Vielen Dank. –

1

Der Code, der Visual Studio automatisch generiert für Sie eine kleine Bedingung tatsächlich besser ist:

public void RaisesMyEvent() 
{ 
    if(MyEvent != null) //required in C# to ensure a handler is attached 
     // Now if someone in another thread sets MyEvent to null the next line will still execute 
     MyEvent(this, new MyEventArgs(/*any info you want handlers to have*/)); 
     // And throw a NullReferenceException 
} 

Dieser Code hat eine Race-Bedingung. Es ist ziemlich selten, es zu treffen, aber es ist möglich. Der Visual Studio-Standardcode vermeidet diese Race-Bedingung, indem er vor dem Aufruf eine lokale Kopie des Event-Handlers erstellt.

Was, wie mehrere Parameter an den Ereignishandler zu übergeben:

Es gibt mehr Möglichkeiten, aber die ‚Standard‘ Art und Weise ist es, eine Klasse zu erstellen, die EventArgs erstreckt. Zum Beispiel erweitert PaintEventArgsEventArgs und fügt eine Graphics und Rectangle Eigenschaften für die OnPaint Handler zu verwenden.

Ich würde diesem grundlegenden Muster folgen, indem ich eine MyEventArgs Klasse basierend auf EventArgs erstellen und die Eigenschaften hinzufügen, die Ihre Methode benötigen wird.

+0

Ich schätze die Zeit, die Sie in diese Antwort setzen. Sehr informativ. –

1

Ersetzen Sie einfach EventArgs mit Ihrem eigenen Klasse:

class MyEventArgs : EventArgs 
{ 
    public string Text { get; private set; } 

    public MyEventArgs(string text) 
    { 
     Text = text; 
    } 
} 

Der EventHandler<T> generic Delegattyp akzeptieren EventArgs oder jede Unterklasse von EventArgs.

Wenn Sie dann OnMyEvent() aufrufen, übergeben Sie einfach eine Instanz Ihrer Klasse mit den Daten, die Sie mit dem Ereignis übermitteln möchten.

Ich stimme den anderen Hinweisen in Bezug auf thread-sicheren Aufruf zu. Dies ist nicht immer erforderlich, aber es ist einfach genug zu implementieren und die IDE-Version ist sicher, während Ihre nicht ist.

+0

Dies ist für eine kontrollierte universelle Anwendung nützlich, um strukturierte Daten zu übergeben, die natürlich beliebig ergänzt werden können. Ich denke, ich hatte ein Hirn furzen auf diesem, würde einfach 'EventHandler ' anstelle von 'EventHandler ' verwenden. –