Может ли анонимный делегат отписаться от события после его запуска? - PullRequest
17 голосов
/ 21 июня 2010

Мне интересно, какова «лучшая практика», когда я обращаюсь к обработчику событий с просьбой отписаться от самого себя после запуска.

Для контекста, это моя ситуация.Пользователь вошел в систему и находится в состоянии готовности для обработки рабочих элементов.Они получают задание, обрабатывают его, а затем снова возвращаются к готовности.На этом этапе они могут захотеть сказать, что они недоступны для большего количества рабочих элементов, но один из них отправляется им в любом случае.Что я хочу сделать, так это разрешить пользователю «ставить в очередь» сообщение «Я недоступен», как только эта операция станет возможной.

public event SomeHandler StateChanged = delegate {};

public void QueueNotAvailable() 
{
    StateChanged += (s,e) => {
                                 if (e.CanGoNotAvailable) { 
                                     someObject.NotAvailable();
                                     StateChanged -= {thishandler};
                                 }
                             }
}

Для моих целей, если отдельный потокслучается, чтобы запустить события, и этот конкретный обработчик запускается дважды, это не проблема.Запрос одной и той же функции очень близко друг к другу является приемлемым.Я просто не хочу, чтобы он стрелял каждый раз, когда операция разрешена.

Ответы [ 3 ]

40 голосов
/ 21 июня 2010

Вы можете сохранить экземпляр делегата перед подпиской на событие:

public void QueueNotAvailable() 
{
    SomeHandler handler = null;
    handler = (s,e) {
        // ...
        StateChanged -= handler;
    };
    StateChanged += handler;
}

Я считаю, что это должно сделать это ... Я должен был поместить туда начальный handler = null, иначе вы получите 'Использование ошибок компиляции «неназначенная локальная переменная», но я думаю, что это на самом деле доброкачественно.

2 голосов
/ 19 ноября 2018

Начиная с C # 7.0, C # поддерживает локальные функции .

Локальные функции - это частные методы типа, которые вложены в другой член. Они могут быть вызваны только из содержащего их члена.

public void QueueNotAvailable() 
{
    void handler(object sender, EventArgs e)
    {
        // do something
        StateChanged -= handler;
    }
    StateChanged += handler;
}
0 голосов
/ 20 июля 2018

Подход, предложенный Дином Хардингом, работает как шарм, но вам нужно добавить 2 строки на событие и имя для каждого обработчика, что делает код более сложным.Чтобы избежать этого, вы можете написать некоторый умный делегат, подобный следующему:

public delegate void SmartAction<T>(SmartAction<T> self, T data);

public event SmartAction<int> ProgressChanged;

ProgressChanged += (self, progress) => 
{ 
  Console.WriteLine(progress);
  ProgressChanged -= self;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...