Es gibt keine einfache Methode, dies zu erreichen.
Preferred Ansatz:
Ich sehe nicht, warum Sie nicht den Delegierten speichern. Sie müssen die Instanz nicht als ein Feld speichern. Es kann eine lokale Variable sein, die von Ihrer anonymen Ereignisbehandlungsroutine erfaßt wird:
EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
// Do whatever you need to do here
// Remove event:
foo.Event -= handler;
}
foo.Event += handler;
ich nicht von einem einzigen Szenario denken kann, wo Sie diese nicht nutzen können.
Alternative Ansatz ohne Speichern der Delegat:
Wenn Sie jedoch ein solches Szenario haben, ist es ziemlich schwierig zu bekommen.
Sie müssen den Delegaten finden, der dem Ereignis als Handler hinzugefügt wurde. Weil Sie es nicht gespeichert haben, ist es ziemlich schwer, es zu erhalten. Es gibt keine this
, um einen Delegaten der aktuell ausgeführten Methode abzurufen.
Sie können nicht GetInvocationList()
auf den Fall entweder verwenden, da ein Ereignis außerhalb der Klasse Zugriff auf sie in beschränkt sich auf das Hinzufügen und Entfernen Handler definiert wird, das heißt +=
und -=
.
Das Erstellen eines neuen Delegaten ist ebenfalls nicht möglich. Während Sie Zugriff auf das Objekt MethodInfo
erhalten können, das Ihre anonyme Methode definiert, können Sie keinen Zugriff auf die Instanz der Klasse erhalten, in der diese Methode deklariert ist. Diese Klasse wird automatisch vom Compiler generiert und der Aufruf this
innerhalb der anonymen Methode gibt das zurück Instanz der Klasse, in der Ihre normale Methode definiert ist.
Der einzige Weg, den ich gefunden habe, ist zu finden, das Feld - falls vorhanden - dass das Ereignis verwendet und GetInvocationList()
darauf aufrufen. Der folgende Code zeigt dies mit einer Dummy-Klasse:
void Main()
{
var foo = new Foo();
foo.Bar += (s, e) => {
Console.WriteLine("Executed");
var self = new StackFrame().GetMethod();
var eventField = foo.GetType()
.GetField("Bar", BindingFlags.NonPublic |
BindingFlags.Instance);
if(eventField == null)
return;
var eventValue = eventField.GetValue(foo) as EventHandler;
if(eventValue == null)
return;
var eventHandler = eventValue.GetInvocationList()
.OfType<EventHandler>()
.FirstOrDefault(x => x.Method == self)
as EventHandler;
if(eventHandler != null)
foo.Bar -= eventHandler;
};
foo.RaiseBar();
foo.RaiseBar();
}
public class Foo
{
public event EventHandler Bar;
public void RaiseBar()
{
var handler = Bar;
if(handler != null)
handler(this, EventArgs.Empty);
}
}
Bitte beachten Sie, dass die Zeichenfolge "Bar"
, den GetField
übergeben wird der genaue Name des Feldes sein muss, die durch das Ereignis verwendet wird. Dies führt zu zwei Problemen:
- Das Feld kann anders benannt werden, z. bei Verwendung einer expliziten Ereignisimplementierung. Sie müssen den Feldnamen manuell herausfinden.
- Möglicherweise gibt es kein Feld. Dies passiert, wenn das Ereignis eine explizite Ereignisimplementierung verwendet und nur an ein anderes Ereignis delegiert oder die Delegierten auf andere Weise speichert.
Fazit:
Der alternative Ansatz stützt sich auf Details der Implementierung, so verwenden Sie es nicht, wenn Sie es vermeiden können.
Es gibt ein paar Muster ist da draußen, die Sie auf Ereignisse in einem * Loosley gekoppelt * Podcatcher ermöglichen. Schauen Sie sich [this] an (http://martinfowler.com/eaaDev/EventAggregator.html). Es beschreibt, wie man einen Event-Aggregator abonniert/abbestellt (in diesem Fall handelt es sich um Bildschirme). Der eigentliche Aggregator erstellt die Referenzen zwischen Objekten. Es gibt viele verschiedene Implementierungen. Die von mir bevorzugte Version ist in [Caliburn.Micro] implementiert (http://www.mindscapehq.com/blog/index.php/2012/02/01/caliburn-micro-part-4-the-event-aggregator/) . –