Rezygnacja z anonimowej metody w C#
Czy można zrezygnować z anonimowej metody Z wydarzenia?
Jeśli subskrybuję takie wydarzenie:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
Mogę zrezygnować z subskrypcji w ten sposób:
MyEvent -= MyMethod;
Ale jeśli subskrybuję metodą anonimową:
MyEvent += delegate(){Console.WriteLine("I did it!");};
Czy można zrezygnować z tej anonimowej metody? Jeśli tak, to w jaki sposób?
11 answers
Action myDelegate = delegate(){Console.WriteLine("I did it!");};
MyEvent += myDelegate;
// .... later
MyEvent -= myDelegate;
Po prostu zachowaj odniesienie do delegata.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-13 19:50:55
Jedną z technik jest zadeklarowanie zmiennej przechowującej metodę anonimową, która byłaby dostępna wewnątrz samej metody anonimowej. Zadziałało to dla mnie, ponieważ pożądanym zachowaniem było wypisanie się po zakończeniu wydarzenia.
Przykład:
MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-08 15:34:51
Z pamięci, Specyfikacja jawnie nie gwarantuje zachowania w żaden sposób, jeśli chodzi o równoważność delegatów utworzonych za pomocą metod anonimowych.
Jeśli chcesz zrezygnować z subskrypcji, powinieneś użyć "normalnej" metody lub zatrzymać delegata w innym miejscu, aby móc zrezygnować z subskrypcji z dokładnie tym samym delegatem, którego użyłeś do subskrypcji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-08 15:26:56
W 3.0 można skrócić do:
MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
Zamiast odwoływać się do dowolnego delegata, możesz użyć swojej klasy, aby przekazać listę wywołania zdarzenia rozmówcy. Zasadniczo możesz napisać coś takiego (zakładając, że MyEvent jest zadeklarowany wewnątrz MyClass):
public class MyClass
{
public event EventHandler MyEvent;
public IEnumerable<EventHandler> GetMyEventHandlers()
{
return from d in MyEvent.GetInvocationList()
select (EventHandler)d;
}
}
Możesz więc uzyskać dostęp do całej listy wywołań spoza MyClass i zrezygnować z subskrypcji dowolnego programu obsługi. Na przykład:
myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
Napisałem pełny post o tym tecnique tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-23 23:11:50
Rodzaj lamerskiego podejścia:
public class SomeClass
{
private readonly IList<Action> _eventList = new List<Action>();
...
public event Action OnDoSomething
{
add {
_eventList.Add(value);
}
remove {
_eventList.Remove(value);
}
}
}
- nadpisuje metody dodawania/usuwania zdarzeń.
- Zachowaj listę tych procedur obsługi zdarzeń.
- w razie potrzeby wyczyść je wszystkie i ponownie dodaj pozostałe.
To może nie działać lub być najbardziej efektywną metodą, ale powinno wykonać zadanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-08 15:37:24
Ponieważ C# 7.0 local functions feature została wydana, podejście zasugerowane przez J c staje się naprawdę schludne.
void foo(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Więc, szczerze mówiąc, nie masz anonimowej funkcji jako zmiennej tutaj. Ale przypuszczam, że motywacja do korzystania z niego w Twoim przypadku może być zastosowana do lokalnych funkcji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-15 05:30:06
Jeśli chcesz mieć możliwość kontrolowania wypisania się, musisz przejść trasę wskazaną w zaakceptowanej odpowiedzi. Jeśli jednak po prostu martwisz się o wyczyszczenie referencji, gdy twoja klasa subskrybująca wychodzi poza zakres, istnieje inne (nieco zawiłe) rozwiązanie, które wymaga użycia słabych referencji. Właśnie zamieściłem pytanie i odpowiedź na ten temat.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:18
Jedno proste rozwiązanie:
Wystarczy przekazać zmienną eventhandle 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:
MyEventHandler foo = null;
foo = (s, ev, mehi) => MyMethod(s, ev, foo);
MyEvent += foo;
void MyMethod(object s, MyEventArgs ev, MyEventHandler myEventHandlerInstance)
{
MyEvent -= myEventHandlerInstance;
Console.WriteLine("I did it!");
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-12 14:11:21
Jeśli chcesz odnieść się do jakiegoś obiektu z tym delegatem, możesz użyć delegata.CreateDelegate (Type, Object target, MethodInfo methodInfo) . NET rozważ, że delegat jest równy przez target i methodInfo
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-21 03:19:30
Jeśli najlepszym sposobem jest zachowanie odniesienia na subskrybowanym eventhandlerze, 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 true włącza zdarzenie, podczas gdy używanie go z false wyłącza.
static Dictionary<DataGridView, PaintEventHandler> subscriptions = new Dictionary<DataGridView, PaintEventHandler>();
public static void MergeColumns(this DataGridView dg, bool enable, params ColumnGroup[] mergedColumns) {
if(enable) {
subscriptions[dg] = (s, e) => Dg_Paint(s, e, mergedColumns);
dg.Paint += subscriptions[dg];
}
else {
if(subscriptions.ContainsKey(dg)) {
dg.Paint -= subscriptions[dg];
subscriptions.Remove(dg);
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-13 06:40:33