2008-11-14 6 views
38

Ich habe eine statische Klasse, die ein Ereignis als Teil eines try catch-Blocks innerhalb einer statischen Methode dieser Klasse auslösen möchte.So lösen Sie ein benutzerdefiniertes Ereignis aus einer statischen Klasse aus

Zum Beispiel möchte ich in dieser Methode ein benutzerdefiniertes Ereignis im Fang auslösen.

public static void saveMyMessage(String message) 
{ 
    try 
    { 
     //Do Database stuff 
    } 
    catch (Exception e) 
     { 
       //Raise custom event here 
     } 
} 

Vielen Dank.

Antwort

88

Wichtig: Seien Sie sehr vorsichtig beim Abonnieren eines statischen Ereignisses von Instanzen. Statisch zu statisch ist in Ordnung, aber eine Subskription von einem statischen Ereignis zu einem Instanz-Handler ist eine großartige (lese: sehr gefährliche) Möglichkeit, diese Instanz für immer am Leben zu erhalten. GC wird den Link sehen und die Instanz nicht sammeln, wenn Sie sich nicht abmelden (oder etwas wie eine WeakReference verwenden).

Das Muster statische Ereignisse für die Erstellung ist die gleiche wie isntance Ereignisse, nur mit static:

public static event EventHandler SomeEvent; 

Um das Leben leichter (re null Kontrolle) zu machen, hier ein nützlicher Trick einen trivialen Handler hinzuzufügen ist:

public static event EventHandler SomeEvent = delegate {}; 

Dann können Sie einfach aufrufen, ohne das null-Check:

SomeEvent(null, EventArgs.Empty); 

Beachten Sie, dass Delegationsinstanzen unveränderlich sind und die De-Referenzierung threadsicher ist. Daher gibt es hier niemals eine Racebedingung und es ist nicht erforderlich, zu sperren, wer immer abonniert ist, wenn die De-Referenz aufgerufen wird.

(passen Sie für Ihre eigenen Event-Args etc). Dieser Trick gilt gleichermaßen für Instanzereignisse.

+0

Beim Lesen Ihrer Antwort haben Sie gesagt: "Eine Subskription von einem statischen Ereignis zu einem Instanz-Handler ist eine großartige Möglichkeit, diese Instanz für immer am Leben zu erhalten", nehme ich an, dass dies nicht immer optimal ist. Wenn ich zum Beispiel eine statische Klasse verwende, um die Formulareinstellungen während der Ausführung zu speichern, ist das nicht so schlimm, da es statisch ist und nicht mehrere Kopien haben kann. (Anfänger Programmierer, vergib die schlechte Terminologie) – Josh

+0

@Josh der "große Weg" war gemeint als "eine wirklich gefährliche Art und Weise" - das habe ich geklärt. Wenn Sie nur ein Abonnement haben, ist dies kein großes Problem, unabhängig davon, ob es sich um eine statische vs -Instanz handelt. Der gefährliche Teil kommt, wenn jede Instanz (sagen wir) ein statisches Ereignis oder ein Ereignis auf einem langlebigen Objekt subskribiert und niemals abmeldet. Hey presto: Speicher verstopfen. –

+1

"Abonnement von einem statischen Ereignis zu einem Instanz-Handler" ist es absichtlich so geschrieben? Ich glaube, dass es stattdessen "Subskription von einem Instanz-Handler ein statisches Ereignis" sein sollte. –

0

Hinweis: VS2008, C#

Nur ein Ereignis erklären, wie Sie normalerweise innerhalb der statischen Klasse wäre, aber sicher sein, das Ereignis als statisch markieren:

public static event EventHandler Work; 

Dann abonnieren Sie es, wie Sie normalerweise würde.

+0

Re "wie Sie normalerweise" - Sie müssen vorsichtiger mit statischen Ereignissen sein, vor allem wieder abbestellen. Das funktioniert in jeder Version von C# BTW. –

10

Ihre Veranstaltung müßte auch statisch sein:

public class ErrorEventArgs : EventArgs 
{ 
    private Exception error; 
    private string message; 

    public ErrorEventArgs(Exception ex, string msg) 
    { 
     error = ex; 
     message = msg; 
    } 

    public Exception Error 
    { 
     get { return error; } 
    } 

    public string Message 
    { 
     get { return message; } 
    } 
} 

public static class Service 
{ 
    public static EventHandler<ErrorEventArgs> OnError; 

    public static void SaveMyMessage(String message) 
    { 
      EventHandler<ErrorEventArgs> errorEvent = OnError; 
     if (errorEvent != null) 
     { 
      errorEvent(null, new ErrorEventArgs(null, message)); 
     } 
    } 
} 

und Verbrauch:

public class Test 
{ 
    public void OnError(object sender, ErrorEventArgs args) 
    { 
     Console.WriteLine(args.Message); 
    } 
} 

Test t = new Test(); 
Service.OnError += t.OnError; 
Service.SaveMyMessage("Test message"); 
+0

+1 es ist so lange her, dass ich Event-Handling schreiben musste Ich konnte mich nicht einmal an die Syntax dafür erinnern. Offenbar, weil ich nur an die 2.0-Syntax denken konnte (das letzte Mal musste ich eine schreiben) und vergaß, dass sie das in 3.5 hinzugefügt –

6

Mehrere Leute haben dargebracht Code-Beispiele, nur nicht über ein Ereignis ausgelöst Code wie:

if(null != ExampleEvent) 
{ 
    ExampleEvent(/* put parameters here, for events: sender, eventArgs */); 
} 

da dies eine Race-Bedingung zwischen, wenn Sie das Ereignis für null und wenn Sie tatsächlich überprüfen feuern Sie das Ereignis ab. Anstatt eine einfache Variante verwenden:

MyEvent exampleEventCopy = ExampleEvent; 
if(null != exampleEventCopy) 
{ 
    exampleEventCopy(/* put parameters here, for events: sender, eventArgs */); 
} 

Dadurch wird alle Ereignisabonnenten in den exampleEventCopy kopieren, die Sie dann als lokale geschützte Version der öffentlichen Veranstaltung über alle Rennbedingungen sorgen, ohne dass (Im Wesentlichen können es verwenden, Es ist möglich, dass ein anderer Thread Sie vorwegnehmen könnte, nachdem Sie das öffentliche Ereignis auf null überprüft und alle Abonnenten aus dem Ereignis entfernt haben, wodurch das anschließende Auslösen des Ereignisses eine Ausnahme auslöst, indem eine lokale Kopie verwendet wird. Sie vermeiden die Möglichkeit, dass ein anderer Thread Abonnenten löscht, da sie auf die lokale Variable nicht zugreifen können.

+7

Eine einfachere Lösung ist: public static event EventHandler Work = delegieren {}; Jetzt ist es nie null und Sie können es einfach aufrufen. Etwas faul, aber nicht genug, um zu verletzen. –

+1

@Mark Verglichen mit dem Kopieren der Delegiertenliste und dem Durchführen eines Null-Checks, glaube ich, einen Delegierten "Nichts machen" schneller und einfacher zu machen. Danke für die Antwort oben. – MindJuice

0

Nur hinzufügen "Delegaten sind unveränderbar" So, wie im obigen Beispiel gezeigt, erhält die folgende Zeile eine Kopie des Delegaten.

EventHandler<ErrorEventArgs> errorEvent = OnError; 
Verwandte Themen