Удаление всех обработчиков событий за один раз - PullRequest
5 голосов
/ 19 июля 2009

Проблема: у меня есть класс документа, который содержит список объектов. Эти объекты вызывают события, такие как SolutionExpired, DisplayExpired и т. Д. Документ должен ответить на это.

Документы могут иногда обмениваться объектами, но один объект никогда не должен быть «частью» более чем одного документа.

Мой класс документов содержит несколько методов, которые служат обработчиками событий. Всякий раз, когда объект входит в документ, я использую AddHandler, чтобы установить события, и всякий раз, когда объект удаляется из документа, я использую RemoveHandler, чтобы устранить повреждение. Однако бывают случаи, когда сложно убедиться, что все шаги выполнены правильно, и поэтому я мог бы получить обработчики мошеннических событий.

Короче говоря; Как удалить все обработчики, которые указывают на определенный метод? Обратите внимание, у меня нет списка потенциальных источников событий, они могут храниться где угодно.

Что-то вроде:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired

Ответы [ 3 ]

5 голосов
/ 27 июля 2009

Вы можете использовать Delegate.RemoveAll(). (Интересующая вас часть находится в button2_Click)

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click);
    button1.Click += new EventHandler(button1_Click);
    button2.Click += new EventHandler(button2_Click);
    TestEvent += new EventHandler(Form_TestEvent);
}
event EventHandler TestEvent;
void OnTestEvent(EventArgs e)
{
    if (TestEvent != null)
        TestEvent(this, e);
}
void Form_TestEvent(object sender, EventArgs e)
{
    MessageBox.Show("TestEvent fired");
}
void button2_Click(object sender, EventArgs e)
{
    Delegate d = TestEvent as Delegate;
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler;
}
void button1_Click(object sender, EventArgs e)
{
    OnTestEvent(EventArgs.Empty);
}

Вы должны заметить, что он не изменяет содержимое делегатов, которые вы ему передаете, он возвращает измененный делегат. Следовательно, вы не сможете изменить события для кнопки, которую вы перетащили в форму из формы, поскольку button1.Click может использовать только += или -=, а не =. Это не скомпилируется:

button1.Click = Delegate.RemoveAll(d, d) as EventHandler;

Кроме того, будьте уверены, что где бы вы ни реализовывали это, вы следите за потенциалом условий гонки . Вы можете получить действительно странное поведение, если удаляете обработчики из события, которое вызывается другим потоком!

1 голос
/ 27 июля 2009

Использовать Delegate.RemoveAll (возможно, использовать отражение, если экземпляр Delegate является частным).

1 голос
/ 19 июля 2009
public class TheAnswer
{
    public event EventHandler MyEvent = delegate { };

    public void RemoveFromMyEvent(string methodName)
    {
        foreach (var handler in MyEvent.GetInvocationList())
        {
            if (handler.Method.Name == methodName)
            {
                MyEvent -= (EventHandler)handler;
            }
        }
    }
}

РЕДАКТИРОВАТЬ 2: Извиняюсь за мое недопонимание - я вижу, что вы совершенно ясно не имели доступа к источникам событий в исходном сообщении.

Самый простой способ решения этой проблемы - реализовать общий словарь привязок объекта к документу. Когда объект входит в документ, проверьте словарь на наличие привязки к другому документу; если есть, удалите обработчики, которые ссылаются на старый документ, прежде чем добавлять их для нового. В любом случае, обновите словарь с новой привязкой.

Я думаю, что в большинстве случаев влияние на производительность и память было бы незначительным: если вы не имеете дело со многими десятками тысяч небольших объектов и часто обмениваетесь ими между документами, накладные расходы памяти каждой пары ключ / значение и снижение производительности для каждая операция поиска должна быть довольно маленькой.

В качестве альтернативы: если вы можете обнаружить (в обработчиках событий документа), что отправитель события больше не имеет отношения к документу, вы можете отсоединить события там.

Это похоже на те идеи, которые вы, возможно, уже отвергли, но, возможно, нет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...