Нужно ли удалять такого рода обработчик событий? - PullRequest
5 голосов
/ 04 марта 2011

Если я создаю класс .NET, который подписывается на событие с помощью анонимной функции, подобной этой:

void MyMethod()
{
   Application.Current.Deactivated += (s,e) => { ChangeAppearance(); };
}

Будет ли этот обработчик событий корневым, чтобы мой класс не собирался?

Если нет, то!Но если так, можете ли вы показать мне синтаксис удаления?Просто использование - = с тем же кодом кажется неправильным.

Ответы [ 4 ]

3 голосов
/ 04 марта 2011

Вы можете использовать «настоящий» метод, как предлагает Саймон Д., или сделать это:

EventHandler handler = null;
handler = (s,e) => { 
    Application.Current.Deactivated -= handler;
    ChangeAppearance();
};
Application.Current.Deactivated += handler;

Поскольку это несколько уродливо и лишает смысла использовать лямбду для краткости, я, вероятно, перейду к рефакторингу метода. Но полезно знать, что еще работает.

Предупреждение : Само собой разумеется, что вы должны быть очень ультра осторожны, чтобы вообще не связываться со значением handler между точкой, в которой вы подписаны на событие, и точкой, где оно есть. фактически вызвано, в противном случае отписаться часть не будет работать правильно.

3 голосов
/ 04 марта 2011

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

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

Если вы слегка измените свою реализацию, чтобы использовать «настоящий» метод, вы можете легкоОтписаться от события так же, как вы подписались на него:

Application.Current.Deactivated += ChangeAppearance;
Application.Current.Deactivated -= ChangeAppearance;
private void ChangeAppearance(object sender, EventArgs eventArgs)
{
    throw new NotImplementedException();
}
2 голосов
/ 05 марта 2011

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

static class MemoryLeak
{
    static List<Action<int>> list = new List<Action<int>>();
    public static event Action<int> ActivateLeak
    {
        add
        {
            list.Add(value);
        }
        remove
        {
            list.Remove(value);
        }
    }
}

Затем, установив точку останова в функции удаления, вы увидите, что ваша ссылка не очищена.

class Program
{
    static void Main(string[] args)
    {
        foo f = new foo();
        MemoryLeak.ActivateLeak += o => f.bar();
        f.tryCleanup();
    }
}

class foo
{
    public void bar()
    { }

    public void tryCleanup()
    {
        MemoryLeak.ActivateLeak -= o => bar();
    }
}

В качестве альтернативы решению Саймона вы можете использовать второе замыкание для создания действия «отсоединения», которое можно обойти.

foo f = new foo();
Action<int> callfoo = o => f.bar();
MemoryLeak.ActivateLeak += callfoo;
Action cleanUp = () => MemoryLeak.ActivateLeak -= callfoo;

// Now you can pass around the cleanUp action and call it when you need to unsubscribe from the event.
cleanUp();
1 голос
/ 04 марта 2011

Это действительно утечка, предотвращающая сборку мусора. Есть способы обойти это - с WeakReference, который является одним из лучших.

Эта ссылка имеет хороший разговор и хорошие ответы для вас.

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