Ответ 1
Спецификация С# явно заявляет (IIRC), что если у вас есть две анонимные функции (анонимные методы или лямбда-выражения), она может или не может создавать равных делегатов из этого кода. (Два делегата равны, если они имеют равные цели и ссылаются на одни и те же методы.)
Конечно, вам нужно запомнить экземпляр делегата, который вы использовали:
EventHandler handler = (s, e) => MessageBox.Show("Woho");
button.Click += handler;
...
button.Click -= handler;
(Я не могу найти соответствующий бит спецификации, но я был бы очень удивлен, увидев, что компилятор С# агрессивно пытается создать равных делегатов. Конечно, было бы неразумно полагаться на него.)
Если вы не хотите этого делать, вам нужно извлечь метод:
public void ShowWoho(object sender, EventArgs e)
{
MessageBox.Show("Woho");
}
...
button.Click += ShowWoho;
...
button.Click -= ShowWoho;
Если вы хотите создать обработчик события, который удаляет себя с помощью лямбда-выражения, он немного сложнее - вам нужно обратиться к делегату внутри самого выражения лямбда, и вы не можете сделать это с помощью простого "объявить локальный переменной и назначить ему, используя выражение лямбда", потому что тогда переменная определенно не назначена. Обычно вы обходите это, сначала назначая нулевое значение переменной:
EventHandler handler = null;
handler = (sender, args) =>
{
button.Click -= handler; // Unsubscribe
// Add your one-time-only code here
}
button.Click += handler;
К сожалению, не так просто инкапсулировать это в метод, потому что события не представлены чисто. Самое близкое, что вы могли бы прийти, было бы что-то вроде:
button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) =>
{
// One-time code here
}, handler => button.Click -= handler);
Даже это было бы сложно реализовать внутри Delegates.AutoUnsubscribe
, потому что вам нужно было бы создать новый EventHandler
(который был бы просто аргументом общего типа). Возможность, но грязная.