我需要删除这种事件处理程序吗?

5
如果我创建一个.NET类,使用匿名函数订阅事件,就像这样:
void MyMethod()
{
   Application.Current.Deactivated += (s,e) => { ChangeAppearance(); };
}

这个事件处理程序会成为根,防止我的类被垃圾回收吗?

如果不会,那太好了!但如果会,你能展示一下移除语法吗?仅仅使用 -= 和相同的代码似乎是错误的。

4个回答

3
我认为你需要取消订阅,因为事件提供者(应用程序)的生命周期 - 或者至少可以存在更长时间 - 比您的消费者更长。因此,每个订阅实例在应用程序仍然存在时死亡将创建内存泄漏。
您正在订阅匿名委托到事件。这就是为什么您无法以相同的方式取消订阅它,因为您无法再次寻址它。实际上,您正在创建该方法的同时订阅,而且不存储任何指向新创建的方法的指针。
如果您稍微更改实现以使用“真正的”方法,则可以轻松地取消订阅事件,就像订阅它一样:
Application.Current.Deactivated += ChangeAppearance;
Application.Current.Deactivated -= ChangeAppearance;
private void ChangeAppearance(object sender, EventArgs eventArgs)
{
    throw new NotImplementedException();
}

感谢确认猜测。- 约翰 - jschroedl

3
您可以选择像Simon D.建议的那样使用“真实”方法,或者按照以下步骤操作:
EventHandler handler = null;
handler = (s,e) => { 
    Application.Current.Deactivated -= handler;
    ChangeAppearance();
};
Application.Current.Deactivated += handler;

由于这样有点丑陋,也违背了使用lambda表达式简洁的初衷,我可能会将其重构为一个方法。但是知道其他功能也是有用的。

警告:不用说你必须非常小心,不要在订阅事件和实际调用之间的任何时候改变 handler 的值,否则取消订阅部分将无法正常工作。


我喜欢这里简洁的风格。对于我的需求来说,这应该完美地工作。感谢您抽出时间写这篇文章! - jschroedl

2

你一定需要清理参考文献。如果有任何疑问,你可以通过自己的静态事件轻松测试,如下所示。

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();
    }
}

作为Simon解决方案的替代方案,您可以使用第二个闭包来创建一个“分离”操作,可以传递。
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
这确实是一个阻止垃圾回收的泄漏问题。有一些方法可以解决它,其中WeakReference是比较好的方法之一。 这个链接有一个很好的讨论和对你有帮助的答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接