myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
   » Plugin für Firefox
   » Plugin für IE
   » Gadget für Windows
» Regeln
» Wie poste ich richtig?
» Datenschutzerklärung
» wbb-FAQ

Mitglieder
» Liste / Suche
» Stadt / Anleitung dazu
» Wer ist wo online?

Angebote
» ASP.NET Webspace
» Bücher
» Zeitschriften
   » dot.net magazin

Ressourcen
» guide to C#
» openbook: Visual C#
» openbook: OO
» MSDN Webcasts
» Search.Net

Team
» Kontakt
» Übersicht
» Wir über uns
» Impressum

» Unsere MiniCity
MiniCity
» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Basistechnologien und allgemeine .NET-Klassen » [Lösung] Problem mit EventHandler [==> fertige Code-Snippets inkl. Erklärung]
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

[Lösung] Problem mit EventHandler [==> fertige Code-Snippets inkl. Erklärung]

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
myCSharp.de
Moderationshinweis von herbivore (07.10.2006 10:42):

Dies ist ein Thread, auf den aus der FAQ verwiesen wird. Bitte keine weitere Diskussion, sondern nur wichtige Ergänzungen und diese bitte knapp und präzise. Vielen Dank!
 
progger progger ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2094.gif


Dabei seit: 05.08.2005
Beiträge: 1.271
Entwicklungsumgebung: Visual Studio 2005; #develop 2
Herkunft: Nähe von München


progger ist offline

[Lösung] Problem mit EventHandler [==> fertige Code-Snippets inkl. Erklärung]

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

hallo,
ich habe ein problem mit dem erstellen von events (bin auch noch neu in C#). ich habe eine methode, die bei dem event aufgerufen werden soll:

C#-Code:
private void Sock_OnJoin(string str_nick,string str_channel)
{
    //....
}

und nun soll das event erstellt werden:

C#-Code:
this.Sock.OnJoin+=new System.EventHandler(this.Sock_OnJoin);

aber wie soll ich die parameter übergeben?
ich hab mir als bsp. das click-event bei einem button angeschaut. da hat das event auch 2 parameter, die beim erstellen eines events aber nicht angegeben werden:

C#-Code:
this.button1.Click += new System.EventHandler(this.button1_Click);

wenn ich das aber bei mir mach, gibt es eine fehlermeldung:

Zitat:
Form1.cs(92): Die Methode 'Form1.Sock_OnJoin(string, string)' stimmt nicht mit dem Delegat 'void System.EventHandler(object, System.EventArgs)' überein.

ich bin über jede hilfe dankbar!
progger
08.08.2005 15:09 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
svenson svenson ist männlich
myCSharp.de-Poweruser/ Experte

Dabei seit: 15.04.2005
Beiträge: 8.746
Entwicklungsumgebung: Visual Studio .NET 2003
Herkunft: Berlin


svenson ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Deine Methode Sock_OnJoin() hat zwei String-Parameter, der SystemEventHandler-Delegate hat auch zwei, aber andere (Object und EventsArgs). Du verwendest entweder den falschen Delegaten oder die Methode hat die falsche Signatur.
08.08.2005 15:21 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.341
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo progger,

die Parameter werden ohnehin nicht beim Registrieren des EventHandlers mitgegeben, sondern erst (und jedesmal neu), wenn die Klasse den Event auslöst.

herbivore
08.08.2005 18:40 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
progger progger ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2094.gif


Dabei seit: 05.08.2005
Beiträge: 1.271
Entwicklungsumgebung: Visual Studio 2005; #develop 2
Herkunft: Nähe von München

Themenstarter Thema begonnen von progger

progger ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

@svenson: ich kapier nicht so ganz was du meinst. sorry, aner ich bin noch neu in C#.
@herbivore: es gibt aber einen fehler wenn ich es einfach so lass.
danke für eure antworten!

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von progger am 08.08.2005 19:14.

08.08.2005 19:14 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.341
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

NICHT empfohlen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo progger,

machmal sagt Code mehr als tausend Worte. So definiert man einen eigenen Event (folgt nicht den Microsoft-Empfehlungen und ist deshalb nicht empfohlen, dazu später mehr):

C#-Code (NICHT EMPFOHLEN):
using System;

public delegate void MyHandler (string str_nick, string str_channel);

public class Test
{
   public event MyHandler MyEvent;

   protected virtual void OnMyEvent (string str_nick, string str_channel)
   {
      MyHandler myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (str_nick, str_channel);
      }
   }

   public void DoSomething ()
   {
      // ...
      OnMyEvent ("herbivore", "mycsharp");
      // ...
   }

}

abstract class App
{
   public static void Main (string [] astrArg)
   {
      Test test = new Test ();

      test.MyEvent += new MyHandler (ThisMyEvent);
      test.DoSomething ();
   }

   public static void ThisMyEvent (string str_nick, string str_channel)
   {
      Console.WriteLine ("ThisMyEvent (" + str_nick + ", "
                                         + str_channel + ")");
   }
}

herbivore

PS: Dieser Code funktioniert zwar, folgt aber nicht der Empfehlung von MS, an die man sich bei Events wirklich besser halten sollte. Wie ein eigener Event nach der Empfehlung von MS aussehen sollte, steht im folgenden Beitrag.
08.08.2005 19:35 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.341
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

[Lösung] sowie weitere Informationen zum Verständnis, zur Definition und Benutzung von Events

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo progger,

und so erstellt man einen eigenen Event von Typ EventHandler (wie es von MS empfohlen wird):

C#-Code (empfohlen):
using System;

public class Test
{
   // --- schnipp ---

   public event EventHandler MyEvent;

   protected virtual void OnMyEvent (EventArgs e)
   {
      EventHandler myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (this, e);
      }
   }

   // --- schnapp ---

   public void DoSomething ()
   {
      // ...
      OnMyEvent (EventArgs.Empty);
      // ...
   }
}

static class App
{
   public static void Main (string [] astrArg)
   {
      Test myObject = new Test ();
      myObject.MyEvent += myObject_MyEvent;

      myObject.DoSomething ();
   }

   public static void myObject_MyEvent (Object objSender, EventArgs e)
   {
      Console.WriteLine ("myObject_MyEvent (" + objSender + ", " + e + ")");
   }
}

EDIT (Das Folgende wurde ergänzt, nachdem der Thread aus der FAQ verlinkt wurde):

Am Ende dieses Beitrags werden Implementierungsvarianten vorgestellt, die Features aus höheren Sprachversionen von C# ( ab 3.0 bzw.  ab 6.0) benutzen und dadurch den Code vereinfachen. Diese Varianten werden bei Nutzung der entsprechenden Sprachversion (und höher) empfohlen.

Eine Implementierungsvariante mit eigener MyEventEventArgs-Klasse findet sich im Beitrag von ThomasR weiter  unten oder für (das inzwischen veraltete) C# 1.x im Beitrag von Programmierhans von weiter  unten.

Hier noch ein Blick auf die wichtigen Bestandteile des Beispiels:


1. Den Event selbst:

C#-Code:
public event EventHandler MyEvent;

Ist in der Klasse definiert, die den Event zur Verfügung stellen will und im Wesentlichen eine Variable, in der die jeweils registrierten EventHandler gespeichert sind. Ist null, wenn kein EventHandler registriert ist. Namen von Events sollten nie mit On beginnen. "MyEvent" ist nur ein Platzhalter, den ihr durch euren Namen für den Event ersetzen solltet, z.B. TextChanged o.ä.


2. Die event-auslösende Methode:

C#-Code:
protected virtual void OnMyEvent (EventArgs a)

Deren Namen sollte immer mit On beginnen und danach sollte der Name des Events folgen. Ist natürlich in der gleichen Klasse definiert. Sie wird von dieser Klasse aufgerufen, um den Event zu feuern. Im Beispiel also in DoSomething in der Zeile OnMyEvent (EventArgs.Empty);

Ab C# 3.0 (bis C# 5.x) kann und sollte man die Implementierung der event-auslösenden Methode durch die Raise-Erweiterungsmethode, die weiter  unten vorgestellt wird, vereinfachen.

Ab C# 6.0 kann und sollte man die Implementierung der event-auslösenden Methode durch den Null-conditional operator, der weiter  unten vorgestellt wird, vereinfachen.


3. Den/die EventHandler:

C#-Code:
public static void myObject_MyEvent (Object objSender, EventArgs e)

Der EventHandler ist in der Klasse definiert, die über das Event informiert werden will. Das ist typischerweise eine andere Klasse, als die, die das Event definiert. Namen von EventHandlern sollten nie mit On beginnen. VS benennt EventHandler nach dem auch hier verwendeten Muster: Variablenname Unterstrich EventName.


4a. Das Registrieren des EventHandler für den Event (auch Abonnieren des Events genannt):

EventHandler werden registriert mit +=

C#-Code (empfohlen):
myObject.MyEvent += myObject_MyEvent;

Unter .NET 1.x musste man noch schreiben:

C#-Code (nicht empfohlen):
myObject.MyEvent += new EventHandler (myObject_MyEvent);

Ab .NET 2.0 ist die kürzere - ansonsten mindestens gleichwertige - Schreibweise möglich, die man unbedingt bevorzugen sollte.


4b. Das Deregistrieren des EventHandler für den Event (auch Entfernen oder Abhängen des EventHandlers genannt):

Zum Deregistrieren eines EventHandlers verwendet man -= statt +=.

Es ist nicht erforderlich, beim Deregistrieren exakt dieselbe Instanz des Delegaten zu verwenden, sondern es reicht, wenn der Delegat auf dieselbe Methode verweist.

C#-Code (nicht empfohlen):
myObject.MyEvent += new EventHandler (myObject_MyEvent);
myObject.MyEvent -= new EventHandler (myObject_MyEvent);

Durch die zweite Zeile wird der EventHandler myObject_MyEvent wieder entfernt, obwohl an sich zwei separate Delegaten-Objekte verwendet werden (new), die aber eben beide auf dieselbe Methode verweisen. Schon deshalb ist die C#-2.0-Schreibweise ohne new vorzuziehen:

C#-Code (empfohlen):
myObject.MyEvent += myObject_MyEvent;
myObject.MyEvent -= myObject_MyEvent;

Das rechtzeitige Deregistrieren von nicht mehr benötigten Events wird oft vergessen. Das kann allerdings negative Konsequenzen haben. Hat ein Objekt B einen Event von Objekt A registriert und wird das Objekt B nicht mehr benötigt, kann die Speicherfreigabe des Objekts B verzögert oder verhindert werden (memory leak). Der Grund ist, dass das Objekt A noch eine Referenz auf das Objekt B hält. Diese Referenz "versteckt" sich im Delegaten für den EventHandler (Delegate.Target). Deshalb sollte man rechtzeitig alle EventHandler die B registriert hat entfernen.

Noch schlimmer ist es, wenn das Objekt B zerstört wird (Dispose) und dabei die EventHandler nicht entfernt werden. Denn wird ein solches Event ausgelöst, wird der weiterhin registrierte EventHandler aufgerufen und dieser greift dann im schlimmsten Fall auf das bereits zerstörte Objekt zu.

+= und -= sind übrigens die einzigen beiden Operatoren, mit denen man auf Events einer Klasse von außen zugreifen kann. Man kann insbesondere nicht abfragen, ob ein EventHandler bereits registriert ist oder nicht. Das ist aber normalerweise gar nicht nötig. Möchte man einen EventHandler entfernen, obwohl man nicht weiß, ob er momentan registriert ist oder nicht, kann man trotzdem -= benutzen. Im Ergebnis ist der EventHandler deregistriert, egal ob er vorher registriert war oder nicht. Möchte man einen EventHandler hinzufügen, aber nur, wenn er nicht bereits registriert ist, benutzt man erst -= und dann +=. Im Ergebnis ist der EventHandler genau einmal registriert, egal ob er vorher registriert war oder nicht. Das gilt natürlich nur, wenn man konsequent ist und es an keiner Stelle zulässt, dass ein EventHandler mehr als einmal registriert wird.


Überlegungen zur Thread-Sicherheit

In vielen Büchern wird in der event-auslösende Methode direkt das Event auf null abgefragt, bevor es gefeuert wird, also so:

C#-Code (nicht empfohlen):
      if (MyEvent != null) {
         MyEvent (this, e);
      }

Auch hier stand bisher der Code so. Dass diese Vorgehensweise nicht thread-sicher ist (zwischen Abfrage und Feuern könnte ein anderer Thread den letzten EventHandler deregistrieren und dann würde das Feuern eine NullReferenceException auslösen), wurde in Kauf genommen, weil viele Klassen sowieso nicht thread-sicher ausgelegt sind und Synchronisierung (z.B. durch lock) nur unnötig Zeit kostet, wenn die Klasse ohnehin nur single-threaded eingesetzt wird.

Es gibt aber eine so preiswerte Lösung, um Thread-Sicherheit zu erreichen, dass man diese grundsätzlich immer einsetzen kann und sollte. Man muss nur dafür sorgen, dass man bei Abfrage und Feuern eine Referenz auf dasselbe Objekt verwendet. Denn Delegaten - und mithin Events - sind immutable. Das Registrieren oder Deregistrieren eines EventHandlers erzeugt immer ein neues Objekt mit den Änderungen. Diesen Umstand kann man nun ausnutzen, denn MyEvent ruft bei jedem Zugriff das jeweils aktuelle Objekt und damit an beiden Stellen ggf. unterschiedliche Objekte ab, wogegen myEvent an beiden Stellen garantiert dasselbe (und da immutable auch unveränderte) Objekt liefert.

C#-Code (empfohlen):
      EventHandler myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (this, e);
      }

Diese Lösung kostet nur eine zusätzlich Referenzzuweisung und spart dabei sogar noch einen Property-Zugriff.

Es sei jedoch darauf hingewiesen, dass trotz oder gerade wegen dieses Vorgehen ein EventHandler auch noch aufgerufen werden kann, *nachdem* er schon aus dem Event ausgetragen (deregistriert) wurde, wodurch sich die Notwendigkeit einer zusätzlichen Synchronisierung ergeben kann.

Dank geht an Golo Roden, der mich auf diese Lösung hingewiesen hat.


Vereinfachung der event-auslösenden Methode bei gleicher Thread-Sicherheit (empfohlen)

Für C# 3.0 bis C# 5.x: Mit der Raise-Erweiterungsmethode, die weiter  unten vorgestellt wird, lässt sich die Implementierung der event-auslösenden Methode bei gleicher Thread-Sicherheit noch einfacher realisieren. Erweiterungsmethoden gibt es ab C# 3.0, so dass wir das vereinfachte Vorgehen ab C# 3.0 (bis C# 5.x) empfehlen.

Für C# 6.0 und höher: Mit dem Null-conditional operator, der weiter  unten vorgestellt wird, lässt sich die Implementierung der event-auslösenden Methode bei gleicher Thread-Sicherheit noch einfacher realisieren. Den Null-conditional operator gibt es ab C# 6.0, so dass wir das vereinfachte Vorgehen ab C# 6.0 empfehlen.


Siehe auch

 [FAQ] Event nur bei Benutzeraktion auslösen, nicht bei programmtechnischer Änderung
 best practise: Event einer aggregierten Klasse weiterleiten


herbivore

Suchhilfe: 1000 Worte
08.08.2005 19:40 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
progger progger ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2094.gif


Dabei seit: 05.08.2005
Beiträge: 1.271
Entwicklungsumgebung: Visual Studio 2005; #develop 2
Herkunft: Nähe von München

Themenstarter Thema begonnen von progger

progger ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Vielen, vielen Dank herbivore. Jetzt hab ichs kapiert. Code sagt wirklich manchmal mehr als 1000 Worte fröhlich
Grüße progger
09.08.2005 10:09 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Programmierhans
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-1651.gif


Dabei seit: 05.04.2005
Beiträge: 4.218
Entwicklungsumgebung: VS / Mono (IOS/LINUX)
Herkunft: Zentralschweiz


Programmierhans ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zur Ergänzung noch ein wenig kopierter Code wie es aussieht mit eigener EventArgs Klasse

[EDIT](der Code in diesem Beitrag ist für .NET bis Version 1.x; wie man es ab .NET machen sollte, zeigt der folgende Beitrag)[/EDIT]

C#-Code:
        public event TextIOEventHandler TextRawReceived;

        protected virtual void OnTextRawReceived(string textReceived)
        {
            TextIOEventHandler textRawReceived = this.TextRawReceived;
            if (textRawReceived!=null)
            {
                textRawReceived(this,new TextIOEventArgs(textReceived));
            }
        }

        public delegate void TextIOEventHandler(object sender, TextIOEventArgs e);

    public class TextIOEventArgs : System.EventArgs
    {
        private readonly string text;
        public TextIOEventArgs(string text) :base()
        {
            this.text=text;
        }
        public string Text
        {get{return this.text;}}
    }

In diesem Beispiel halt nur mit einem Attribut.
09.08.2005 11:41 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 2 Jahre.
ThomasR ThomasR ist männlich
myCSharp.de-Mitglied

Dabei seit: 28.10.2007
Beiträge: 93


ThomasR ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

ich hätte zum Thema eigene EventArgs noch eine Ergänzung. Noch schicker (und von Microsoft ab .NET 2.0 auch empfohlen) ist die Möglichkeit mit Generics. Dadurch erspart man sich die Definition eines eigenen delegates...Ich habe den vorigen Codeausschnitt mal daraufhin angepasst.

C#-Code:
public event EventHandler<TextIOEventArgs> TextRawReceived;

        protected virtual void OnTextRawReceived(string textReceived)
        {
            EventHandler<TextIOEventArgs> textRawReceived = this.TextRawReceived;
            if (textRawReceived!=null)
            {
                textRawReceived(this,new TextIOEventArgs(textReceived));
            }
        }


    public class TextIOEventArgs : System.EventArgs
    {
        private readonly string text;
        public TextIOEventArgs(string text) :base()
        {
            this.text=text;
        }
        public string Text
        {get{return this.text;}}
    }
22.05.2008 17:18 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegt mehr als ein Jahr.
herbivore
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.341
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

[Lösung] ab C# 3.0: Extensionmethod zum Auslösen von Events

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

weiter  oben wird vorgeschlagen, Events wie folgt zu definieren:

C#-Code:
   public event EventHandler <EventArgs> MyEvent;

   protected virtual void OnMyEvent (EventArgs e)
   {
      EventHandler <EventArgs> myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (this, e);
      }
   }

Bei Events hat mich schon immer geärgert, dass man diese auf null abfragen muss, bevor man sie feuern kann. Mit folgender Erweiterungsmethode

C#-Code:
public static void Raise <T> (this EventHandler <T> eventHandler, Object sender, T e) where T : EventArgs
{
   if (eventHandler != null) {
      eventHandler (sender, e);
   }
}

kann man das Codestück

C#-Code:
EventHandler <EventArgs> myEvent = MyEvent;
if (myEvent != null) {
   myEvent (this, e);
}

durch - so ist es ab C# 3.0 (bis C# 5.x) empfohlen -

C#-Code (empfohlen ab C# 3.0 (bis C# 5.x)):
MyEvent.Raise (this, e);

ersetzen (siehe  oben für weitere Informationen zum Verständnis, zur Definition und Benutzung von Events).

Da es sich um eine Erweiterungsmethode handelt, wird diese auch dann aufgerufen, wenn das Event null ist. Es gibt im Gegensatz zu normalen Methoden hier keine NullReferenceException.

Außerdem ist die Variante mit der Erweiterungsmethode auf die gleiche Weise threadsafe wie der bisherige Code. Die Begründung ist die gleiche, nur dass keine zusätzliche lokale Variable benötigt wird, sondern die Variable für den Parameter eventHandler diese Aufgabe übernimmt.

Selbst beim Inlining der Erweiterungsmethode darf der Compiler die Variable für den Parameter nicht wegoptimieren, genausowenig wie der Compiler die lokale Variable im bisherigen Code wegoptimieren darf. Das liegt an dem mit .NET 2.0 eingeführten ".NET Memory Model", nach dem es dem Compiler und dem JIT nicht erlaubt ist, Zugriffe auf eine Variable auf dem Stack durch Zugriffe auf eine Variable auf dem Heap zu ersetzen.

Die Erweiterungsmethode heißt Raise entsprechend der MSDN-Benennungskonvention "Do use the raise terminology for events rather than fire or trigger" (siehe  Event Design).

Siehe auch  Weitere Informationen zum Verständnis, zur Definition und Benutzung von Events in diesem Thread weiter oben.

herbivore
20.05.2010 08:57 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 5 Jahre.
herbivore
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.341
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

[Lösung] ab C# 6.0: Null-conditional operator beim Auslösen von Events

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

weiter  oben wird vorgeschlagen, Events wie folgt zu definieren:

C#-Code:
   public event EventHandler <EventArgs> MyEvent;

   protected virtual void OnMyEvent (EventArgs e)
   {
      EventHandler <EventArgs> myEvent = MyEvent;
      if (myEvent != null) {
         myEvent (this, e);
      }
   }

Bei Events hat mich schon immer geärgert, dass man diese auf null abfragen muss, bevor man sie feuern kann. Mit dem mit C# 6.0 eingeführten Null-conditional operator (auch Null-propagation operator genannt) kann man sich diese Abfrage bzw. die im vorigen Beitrag vorgeschlagene Erweiterungsmethode sparen.

Man kann im angegebenen Code das Codestück

C#-Code:
EventHandler <EventArgs> myEvent = MyEvent;
if (myEvent != null) {
   myEvent (this, e);
}

einfach durch - so ist es für C# 6.0 und höher empfohlen -

C#-Code (empfohlen ab C# 6.0):
MyEvent?.Invoke (this, e);

ersetzen (siehe  oben für weitere Informationen zum Verständnis, zur Definition und Benutzung von Events).

Die Variante mit dem Null-conditional operator ist auf die gleiche Weise threadsafe wie der bisherige Code. Die Begründung ist die gleiche, nur dass keine zusätzliche lokale Variable benötigt wird, sondern eine interne Variable des Null-conditional operator diese Aufgabe übernimmt. Der Null-conditional operator wertet also MyEvent nur einmal aus, obwohl er dies intern einmal auf null abfragt und ggf. einmal Invoke dafür aufruft.

Siehe auch  Weitere Informationen zum Verständnis, zur Definition und Benutzung von Events in diesem Thread weiter oben.

herbivore


PS: Invoke ist eine Methode, die jeder Delegat besitzt, um ihn aufzurufen. Zwar kann man einen Delegaten auch über seinen Namen aufrufen,

C#-Code (normale Aufrufsyntax):
MyEvent (this, e);

aber den Null-conditional operator darf man bei dieser Aufrufsyntax nicht verwenden. Man darf also nicht schreiben

C#-Code (NICHT erlaubte Syntaxkombination):
MyEvent? (this, e);

Da man aber jeden Delegaten auch über Invoke aufrufen kann,

C#-Code (alternative Aufrufsyntax):
MyEvent.Invoke (this, e);

verwendet man eben diese Aufrufvariante, um sie mit dem Null-conditional operator zu kombinieren. So erklärt sich, wie man zur oben verwendeten Syntax kommt:

C#-Code (korrekt kombinierte Aufrufsyntax):
MyEvent?.Invoke (this, e);
05.04.2016 08:34 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 11 Jahre.
Der letzte Beitrag ist älter als ein Jahr.
Antwort erstellen


© Copyright 2003-2017 myCSharp.de-Team. Alle Rechte vorbehalten. 28.06.2017 16:08