Nie ma prostej metody, aby to osiągnąć.
Preferowane podejście:
ja nie rozumiem, dlaczego nie można zapisać delegata. Nie musisz zapisywać instancji jako pola. Może to być lokalna zmienna, która jest opanowana przez anonimowego obsługi zdarzeń:
EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
// Do whatever you need to do here
// Remove event:
foo.Event -= handler;
}
foo.Event += handler;
Nie mogę myśleć o jednym scenariuszu, gdzie nie można używać.
Alternatywne podejście bez zapisywania delegata:
Jednakże, jeśli masz taki scenariusz, to się dość trudne.
Musisz znaleźć delegata, który został dodany jako przewodnik do zdarzenia. Ponieważ go nie zapisałeś, dość trudno jest go uzyskać. Nie ma potrzeby uzyskiwania delegata aktualnie wykonywanej metody.
Nie można używać GetInvocationList()
na razie obaj, ponieważ dostęp do zdarzenia poza klasą jest zdefiniowany w ogranicza się do dodawania i usuwania teleskopowe, tj +=
i -=
.
Utworzenie nowego uczestnika nie jest również możliwe. Chociaż można uzyskać dostęp do obiektu MethodInfo
definiującego metodę anonimową, nie można uzyskać dostępu do instancji klasy, dla której została zadeklarowana metoda. Ta klasa jest generowana automatycznie przez kompilator, a wywołanie metody anonimowej powoduje zwrócenie wartości instancja klasy, którą twoja normalna metoda jest zdefiniowana w.
Jedynym sposobem, jaki udało mi się znaleźć, jest znalezienie pola - jeśli takie jest -, które zdarzenie używa i zadzwoń pod numer GetInvocationList()
. Poniższy kod demonstruje to z manekina klasy:
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);
}
}
Należy pamiętać, że ciąg "Bar"
który jest przekazywany do GetField
musi być dokładna nazwa pola , który jest używany przez zdarzenie. Powoduje to dwa problemy:
- Pole może mieć różną nazwę, np. podczas korzystania z jawnej implementacji zdarzenia. Musisz ręcznie znaleźć nazwę pola.
- Może nie być żadnego pola. Dzieje się tak, jeśli zdarzenie korzysta z jawnej implementacji zdarzenia i po prostu przekazuje je innemu zdarzeniu lub przechowuje delegatów w inny sposób.
Wniosek:
Alternatywne podejście polega na szczegóły wykonania, więc nie należy go używać, jeśli można tego uniknąć.
Istnieje kilka wzorów, które obecnie nie pozwalają zapisać się do wydarzeń w sprzężonym * * loosley sposób. Sprawdź [to] (http://martinfowler.com/eaaDev/EventAggregator.html). Opisuje sposób zasubskrybowania/wypisania się z agregatora zdarzeń (w tym przypadku dotyczy on ekranów). Rzeczywisty agregator tworzy odwołania między obiektami. Istnieje wiele różnych implementacji. Ten, który preferuję, jest zaimplementowany w [Caliburn.Micro] (http://www.mindscapehq.com/blog/index.php/2012/02/01/caliburn-micro-part-4-the-event-aggregator/) . –