Вопрос

Возьмем следующий класс C #:

c1 {
 event EventHandler someEvent;
}

Если есть много подписок на c1's someEvent событие, и я хочу очистить их все, каков наилучший способ добиться этого? Также учтите, что подписки на это событие могут быть / являются лямбдами / анонимными делегатами.

В настоящее время мое решение состоит в том, чтобы добавить ResetSubscriptions() способ получения c1 это устанавливает someEvent до нуля.Я не знаю, имеет ли это какие-то невидимые последствия.

Это было полезно?

Решение

Изнутри класса вы можете присвоить (скрытой) переменной значение null.Нулевая ссылка - это канонический способ эффективного представления пустого списка вызовов.

Извне класса вы не можете этого сделать - события в основном отображают "подписаться" и "отписаться", и все.

Стоит быть в курсе того, что на самом деле делают события, подобные полю, - они создают переменную и событие в одно и то же время.Внутри класса вы в конечном итоге ссылаетесь на переменную.Извне вы ссылаетесь на событие.

Видишь мой статья о мероприятиях и делегатах для получения дополнительной информации.

Другие советы

Добавьте метод в c1, который установит для 'SomeEvent' значение null...

class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = null;}
}
class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = delegate{};}
}

Лучше использовать delegate{}, чем null

Установка событию значения null внутри класса работает.Когда вы удаляете класс, вы всегда должны устанавливать событию значение null, у GC возникают проблемы с событиями, и он может не очистить удаленный класс, если в нем есть зависшие события.

Лучший способ очистить всех подписчиков - установить для SomeEvent значение null, добавив другой общедоступный метод, если вы хотите предоставить эту функциональность внешним пользователям.Это не имеет невидимых последствий.Предварительным условием является не забыть объявить SomeEvent с ключевым словом 'event'.

Пожалуйста, ознакомьтесь с книгой - C # 4.0 in the nutshell, страница 125.

Кто-то здесь предложил использовать Delegate.RemoveAll способ.Если вы используете его, пример кода может следовать приведенной ниже форме.Но это действительно глупо.Почему бы просто не SomeEvent=null внутри ClearSubscribers() функция?

   public void ClearSubscribers ()
    {
          SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);// Then you will find SomeEvent is set to null.
    }

Вы можете достичь этого с помощью метода Delegate.Remove или Делегировать.Методы removeAll.

Концептуальный расширенный скучный комментарий.

Я предпочитаю использовать слово "обработчик событий" вместо "событие" или "делегат".И использовал слово "событие" для обозначения других вещей.В некоторых языках программирования (VB.NET, Object Pascal, Objective-C) "событие" называется "сообщением" или "сигналом" и даже имеет ключевое слово "message" и специфический синтаксис sugar.

const
  WM_Paint = 998;  // <-- "question" can be done by several talkers
  WM_Clear = 546;

type
  MyWindowClass = class(Window)
    procedure NotEventHandlerMethod_1;
    procedure NotEventHandlerMethod_17;

    procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener
    procedure DoClearEventHandler; message WM_Clear;
  end;

И, чтобы ответить на это "сообщение", отвечает "обработчик событий", будь то один делегат или несколько делегатов.

Краткие сведения:"Событие" - это "вопрос", "обработчики событий" - это ответ (ы).

Это мое решение:

public class Foo : IDisposable
{
    private event EventHandler _statusChanged;
    public event EventHandler StatusChanged
    {
        add
        {
            _statusChanged += value;
        }
        remove
        {
            _statusChanged -= value;
        }
    }

    public void Dispose()
    {
        _statusChanged = null;
    }
}

Тебе нужно позвонить Dispose() или использовать using(new Foo()){/*...*/} шаблон для отмены подписки на всех участников списка вызовов.

Удалите все события, предположим, что событие относится к типу "Действие".:

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top