Czy można anulować anonimową metodę ze zdarzenia?
Jeśli zasubskrybuję takie wydarzenie:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
Mogę anulować subskrypcję w ten sposób:
MyEvent -= MyMethod;
Ale jeśli zasubskrybuję za pomocą anonimowej metody:
MyEvent += delegate(){Console.WriteLine("I did it!");};
czy można zrezygnować z tej anonimowej metody? Jeśli tak to jak?
Odpowiedzi:
Wystarczy zachować odniesienie do delegata w pobliżu.
źródło
Jedną z technik jest zadeklarowanie zmiennej przechowującej anonimową metodę, która byłaby wówczas dostępna w samej metodzie anonimowej. To działało dla mnie, ponieważ pożądanym zachowaniem było anulowanie subskrypcji po zakończeniu wydarzenia.
Przykład:
źródło
Z pamięci specyfikacja wyraźnie nie gwarantuje takiego zachowania, jeśli chodzi o równoważność delegatów utworzonych za pomocą anonimowych metod.
Jeśli musisz anulować subskrypcję, powinieneś albo użyć „normalnej” metody, albo zachować delegata w innym miejscu, abyś mógł zrezygnować z dokładnie tego samego delegata, którego subskrybowałeś.
źródło
W 3.0 można skrócić do:
źródło
Od czasu wydania funkcji funkcji lokalnych w języku C # 7.0 podejście sugerowane przez J c staje się naprawdę czyste.
Tak więc, szczerze mówiąc, nie masz tutaj anonimowej funkcji jako zmiennej. Ale przypuszczam, że motywację do użycia go w twoim przypadku można zastosować do funkcji lokalnych.
źródło
Zamiast utrzymywać odniesienie do dowolnego delegata, możesz instrumentować swoją klasę, aby zwrócić listę wywołań wydarzenia z powrotem do osoby dzwoniącej. Zasadniczo możesz napisać coś takiego (zakładając, że MyEvent jest zadeklarowany w MyClass):
Aby uzyskać dostęp do całej listy wywołań spoza MyClass i anulować subskrypcję dowolnego programu obsługi. Na przykład:
Tutaj napisałem pełny post o tej technice .
źródło
Rodzaj kulawego podejścia:
Może to nie działać lub być najbardziej wydajną metodą, ale powinno zakończyć pracę.
źródło
Jeśli chcesz kontrolować rezygnację z subskrypcji, musisz wybrać trasę wskazaną w zaakceptowanej odpowiedzi. Jeśli jednak obawiasz się o wyczyszczenie referencji, gdy klasa subskrybująca wykracza poza zakres, istnieje inne (nieco skomplikowane) rozwiązanie polegające na użyciu słabych referencji. Właśnie opublikowałem pytanie i odpowiedź na ten temat.
źródło
Jedno proste rozwiązanie:
wystarczy przekazać zmienną uchwytu zdarzenia jako parametr do siebie. Zdarzenie, jeśli masz przypadek, że nie możesz uzyskać dostępu do oryginalnej utworzonej zmiennej z powodu wielowątkowości, możesz użyć tego:
źródło
MyEvent -= myEventHandlerInstance;
zostanie uruchomiony? Jeśli to możliwe, wystąpiłby błąd. Ale nie jestem pewien, czy tak jest.jeśli chcesz odwołać się do jakiegoś obiektu z tym delegatem, być może możesz użyć Delegate.CreateDelegate (typ, obiekt docelowy, MethodInfo methodInfo) .net uważa, że delegat jest równy według celu i methodInfo
źródło
Jeśli najlepszym sposobem jest zachowanie odwołania do subskrybowanego modułu obsługi zdarzenia, można to osiągnąć za pomocą słownika.
W tym przykładzie muszę użyć anonimowej metody, aby dołączyć parametr mergeColumn dla zestawu DataGridViews.
Użycie metody MergeColumn z parametrem enable ustawionym na wartość true włącza zdarzenie podczas korzystania z parametru false powoduje wyłączenie
źródło