Возьмем следующий класс C #:
c1 {
event EventHandler someEvent;
}
Если есть много подписок на c1
«S someEvent
события , и я хочу , чтобы очистить их все, что является лучшим способом для достижения этой цели? Также учтите, что подписки на это событие могут быть лямбда-выражениями / анонимными делегатами.
В настоящее время мое решение - добавить ResetSubscriptions()
метод, для c1
которого установлено someEvent
значение null. Не знаю, есть ли у этого какие-то невидимые последствия.
EventHandlerList
, вы можете это сделать. Однако вам придется распознать эти два случая - и может быть любое количество других реализаций.hidden
.Добавьте в c1 метод, который установит для someEvent значение null.
public class c1 { event EventHandler someEvent; public ResetSubscriptions() => someEvent = null; }
источник
class c1 { event EventHandler someEvent; ResetSubscriptions() => someEvent = delegate { }; }
Лучше использовать,
delegate { }
чемnull
избегать исключения null ref.источник
List.Clear()
противmyList = null
.Установка события в значение null внутри класса работает. Когда вы удаляете класс, вы всегда должны устанавливать для события значение null, GC имеет проблемы с событиями и может не очистить удаленный класс, если у него есть висячие события.
источник
Лучшая практика для очистки всех подписчиков - установить для someEvent значение null, добавив еще один общедоступный метод, если вы хотите предоставить эту функцию извне. Это не имеет невидимых последствий. Предварительное условие - не забудьте объявить SomeEvent с ключевым словом 'event'.
См. Книгу - Краткое описание C # 4.0, стр. 125.
Кто-то здесь предложил использовать
Delegate.RemoveAll
метод. Если вы его используете, образец кода может соответствовать приведенной ниже форме. Но это действительно глупо. Почему не толькоSomeEvent=null
внутриClearSubscribers()
функции?public void ClearSubscribers () { SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent); // Then you will find SomeEvent is set to null. }
источник
public delegate string TableNameMapperDelegate(Type type);public static TableNameMapperDelegate TableNameMapper;
?Этого можно добиться с помощью методов Delegate.Remove или Delegate.RemoveAll.
источник
Концептуальный расширенный скучный комментарий.
Я предпочитаю использовать слово «обработчик событий» вместо «событие» или «делегат». И использовал слово «событие» для других вещей. В некоторых языках программирования (VB.NET, Object Pascal, Objective-C) «событие» называется «сообщением» или «сигналом» и даже имеет ключевое слово «сообщение» и особый синтаксис сахара.
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; } }
источник
GetInvocationList
.Вместо того, чтобы добавлять и удалять обратные вызовы вручную и везде объявлять кучу типов делегатов:
// The hard way public delegate void ObjectCallback(ObjectType broadcaster); public class Object { public event ObjectCallback m_ObjectCallback; void SetupListener() { ObjectCallback callback = null; callback = (ObjectType broadcaster) => { // one time logic here broadcaster.m_ObjectCallback -= callback; }; m_ObjectCallback += callback; } void BroadcastEvent() { m_ObjectCallback?.Invoke(this); } }
Вы можете попробовать этот общий подход:
public class Object { public Broadcast<Object> m_EventToBroadcast = new Broadcast<Object>(); void SetupListener() { m_EventToBroadcast.SubscribeOnce((ObjectType broadcaster) => { // one time logic here }); } ~Object() { m_EventToBroadcast.Dispose(); m_EventToBroadcast = null; } void BroadcastEvent() { m_EventToBroadcast.Broadcast(this); } } public delegate void ObjectDelegate<T>(T broadcaster); public class Broadcast<T> : IDisposable { private event ObjectDelegate<T> m_Event; private List<ObjectDelegate<T>> m_SingleSubscribers = new List<ObjectDelegate<T>>(); ~Broadcast() { Dispose(); } public void Dispose() { Clear(); System.GC.SuppressFinalize(this); } public void Clear() { m_SingleSubscribers.Clear(); m_Event = delegate { }; } // add a one shot to this delegate that is removed after first broadcast public void SubscribeOnce(ObjectDelegate<T> del) { m_Event += del; m_SingleSubscribers.Add(del); } // add a recurring delegate that gets called each time public void Subscribe(ObjectDelegate<T> del) { m_Event += del; } public void Unsubscribe(ObjectDelegate<T> del) { m_Event -= del; } public void Broadcast(T broadcaster) { m_Event?.Invoke(broadcaster); for (int i = 0; i < m_SingleSubscribers.Count; ++i) { Unsubscribe(m_SingleSubscribers[i]); } m_SingleSubscribers.Clear(); } }
источник