2009-06-11 13 views
0

OK, ich habe es versucht, aber ich verstehe es einfach nicht.Hinzufügen eines Ereignisses zu einer Klassenmethode?

Ich habe zwei Klassen logger und class1.

Ich habe eine Methode namens logger.Write(string) und Methode namens class1.Execute().

Jetzt in meiner Anwendung möchte ich logger.Write(class1.ToString()) ausgeführt haben, wenn class1.Execute() aufgerufen wird.

Ich nehme an, dass Sie Delegierte und Ereignisse hinzufügen müssen, aber ich kann es einfach nicht verstehen, ich habe es ein paar Stunden gekratzt.

Eine Sache ist, dass der Logger und die Klasse in verschiedenen Namespaces sind und ich möchte den Klassencode für beide nicht aktualisieren, wenn möglich.

+0

Was ist falsch mit Jasonhs Vorschlag? – RCIX

+0

Der Vorschlag von jasonh erstellt eine Methode, die die anderen Methoden aufruft. Ich war auf der Suche nach einer Implementierung von Event-Methoden, da ich immer noch versuche zu verstehen, wie sie funktionieren. Jons Beschreibung funktioniert und ich verstehe jetzt, wie man sie implementiert, ich muss jetzt nur verstehen, wie sie funktionieren. –

+0

Es scheint immer noch eine Menge zusätzlicher Arbeit zu sein, wenn eine Erweiterungsmethode den Job prägnant erledigt. Ich verstehe, wenn Sie es verwenden möchten, um zu lernen, wie Ereignismethoden funktionieren, aber ich glaube nicht, dass ich das im Produktionscode verwenden würde, wenn eine 5-Zeilen-Erweiterungsmethode genauso gut funktioniert. – jasonh

Antwort

6

Nun, Sie können es sicherlich nicht tun, ohne Code in beiden Klassen zu ändern (vorausgesetzt, Sie wollen auch nicht überall, dass class1.Execute ruft) - zumindest nicht ohne einige tiefe Code-Weaving/Instrumentierung Magie. Sie können jedoch ziemlich leicht ein Ereignis in Class1 hinzufügen:

public class Class1 
{ 
    // TODO: Think of a better name :) 
    public event EventHandler ExecuteCalled = delegate {}; 

    public void Execute() 
    { 
     ExecuteCalled(this, EventArgs.Empty); 
     // Do your normal stuff 
    } 
} 

Das delegate{} Bit nur um sicher zu machen, ist, dass es immer mindestens ein no-op-Ereignishandler registriert - es bedeutet, dass Sie nicht zu überprüfen, müssen für Nichtigkeit.

Sie würden dann durch Schreiben Haken:

Class1 class1 = new Class1(); 
Logger logger = new Logger(); 
class1.ExecuteCalled += (sender, args) => logger.Write(sender.ToString()); 

(Dies wird vorausgesetzt, Sie C# 3, so haben Sie Lambda-Ausdrücke für Sie verwenden - lassen Sie mich wissen, wenn das nicht der Fall ist.)

Wenn Class1 eine Schnittstelle implementiert (zB IFoo), könnten Sie eine Implementierung der Schnittstelle schreiben möchten, die eine andere Implementierung wickelt und protokolliert kurz vor jedem Aufruf:

public sealed class LoggingFoo : IFoo 
{ 
    private readonly IFoo original; 
    private readonly IFoo logger; 

    public LoggingFoo(IFoo original, Logger logger) 
    { 
     // TODO: Check arguments for nullity 
     this.original = original; 
     this.logger = logger; 
    } 

    // Implement IFoo 
    public void Execute() 
    { 
     logger.Write("Calling Execute on {0}", original); 
     original.Execute(); 
    } 
} 

Dann verwenden Sie einfach diesen Wrapper um eine "echte" Implementierung, wo immer Sie gerade die Implementierung verwenden.

+0

Ist das nicht, was eine Verlängerungsmethode entworfen wurde? – jasonh

+0

Das ist perfekt. Jetzt muss ich nur verstehen, wie es funktioniert. Ich bekomme den ersten Teil, aber ich nehme an, dass der Teil nach dem => der Teil ist, der den Delegaten {} im Ereignishandler in class1 ersetzt. –

+0

@Coding Monkey: => bedeutet Lambda-Ausdruck. In diesem Fall ist es nur eine einfache Möglichkeit, einen Delegierten zu erstellen. Er ersetzt * den ursprünglichen No-Op-Handler nicht; Es fügt einen * neuen * Handler hinzu. Wird mit einem Link zu meinem Veranstaltungsartikel bearbeitet, wenn ich wieder auf einem PC bin. –

2

Können Sie einen Objektparameter für den Logger übergeben und dann einfach den ToString aufrufen? Die richtige ToString-Methode wird aufgerufen. Wenn Sie in Logger oder Klasse1 nichts ändern möchten, können Sie eine Erweiterungsmethode schreiben und diese aufrufen, anstatt class1.Execute aufzurufen. Diese Methode würde den Aufruf zum Logger und dann den Aufruf von class1.Execute machen.

public static ExecuteAndLog(this class1 obj) 
{ 
    logger.Write(obj.ToString()); 
    obj.Execute(); 
} 

Und dann würden Sie rufen Sie einfach obj.ExecuteAndLog();

+0

Hmm das funktioniert eigentlich gut, aber ich müsste die Anrufe ändern. Den Event-Handler verwenden, der eigentlich in meiner Klasse hätte sein sollen. –

+0

Nun, ich bin dann etwas verwirrt. Sie sagen, dass Sie Ihre App, class1 oder logger nicht ändern möchten? Wie bekommst du das Event-System? – jasonh

+0

Ich meinte, dass ich die Klasse nach Möglichkeit nicht aktualisieren wollte, aber was ich wirklich sagen wollte war, dass ich nicht wollte, dass die Klassen aufeinander angewiesen sind. –

0

Sie benötigen ein EventHandler für Class1

public event EventHandler OnExecute; 

und in der Execute-Methode zu deklarieren:

public void Execute() 
{ 
    //... 
    if (OnExecute != null) 
     OnExecute(this, null); 
} 

Und dann, wenn Sie class1 an anderer Stelle verwenden, das ist, wo Sie Ihre Veranstaltung setzen;

private Class1 class1 = new Class1(); 
class1.OnExecute += SomeMethodName; 

public void SomeMethodName(sender obj, EventArgs e) 
{ 
    logger.Write(class1.ToString()); 
} 

Wir können Gewohnheit EventHandlers für machen, wenn Sie mehr Informationen wünschen, aber für Barebones parameterlos Ereignisse sollte diese Arbeit.

Verwandte Themen