C# 取消注册所有事件以释放内存

C# 取消注册所有事件以释放内存,c#,events,C#,Events,我有一个程序,可以编辑产品信息。我注意到它在关闭编辑表单后并没有释放内存。经过一些研究,我偶然发现了一个问题,其中提到问题可能在于它依赖于活动订阅 这对我来说是有意义的,因为这个表单上有大约100多个控件,其中许多是自定义的,由它们的父控件订阅自定义事件。这将创建一个相当大的事件订阅层次结构。所以我寻找了一种发布这些信息的方法,并找到了一种可以让你取消订阅该活动的方法 问题是,我有大量的订阅。我真的必须在表单关闭时一个接一个地手动取消订阅每个事件吗,或者至少有一种方法可以一次性释放它们,或者循环

我有一个程序,可以编辑产品信息。我注意到它在关闭编辑表单后并没有释放内存。经过一些研究,我偶然发现了一个问题,其中提到问题可能在于它依赖于活动订阅

这对我来说是有意义的,因为这个表单上有大约100多个控件,其中许多是自定义的,由它们的父控件订阅自定义事件。这将创建一个相当大的事件订阅层次结构。所以我寻找了一种发布这些信息的方法,并找到了一种可以让你取消订阅该活动的方法


问题是,我有大量的订阅。我真的必须在表单关闭时一个接一个地手动取消订阅每个事件吗,或者至少有一种方法可以一次性释放它们,或者循环使用它们吗?

记住:
+=
左侧的对象使
+=
右侧包含方法的对象保持活动状态。也就是说,引发事件的对象使处理事件的对象保持活动状态,即使处理事件的对象(如窗体)已被释放

所以你需要确保所有的活动发起人都离开了

但是,如果所有事件引发器恰好是订阅这些事件的同一
表单
类中的控件,则在表单关闭时不需要手动解除所有事件处理程序的挂钩

这是因为引发表单订阅的事件的控件与表单本身具有相同的生存期


如果订阅的对象的生命周期比正在订阅的对象的生命周期长,则只需担心。然后,订阅对象(表单)需要在其(表单)被释放时取消订阅。

这取决于您的表单及其事件的生存时间

但是,您可以在表单中循环控件,释放事件。 如果您意外地删除了一个不存在的事件,不用担心,它不会抛出异常

例如,这是如何清除所有TextBox.KeyDown-Events的方法:

  private void frm_FormClosed(object sender, FormClosedEventArgs e)
    {
    foreach (Control tb in this.Controls)
    {
        if (tb is TextBox)
        {
            TextBox tb1 = (TextBox)tb;
            tb1.KeyDown -= TextBox_KeyDown;
        }
    }

可能会研究弱事件模式:因此在这样的情况下:Form=>Control1=>Control2,每个订阅其右边的事件,只要Control2先执行,级联应该是好的,并且所有事件都正确释放?@Nick是的,如果表单(直接或间接)包含这两个控件,那么应该是好的。一旦表单被释放,就无法从任何活动对象访问控件-但这假设您在任何地方都没有对表单的任何引用!如果你这样做了,不管它是否被处理掉——它仍然是可访问的,所以在这种情况下,它和它的所有控件仍然是活动的。因此,在任何地方都不要对表单进行任何非空引用是非常重要的!好的,如果在菜单项中创建并显示表单,则单击事件,而不引用该表单。理论上,当窗体关闭时,它的所有子控件以及它们各自的事件都应该被释放?@Nick:是的,它应该被释放。但从理论上讲,表单可以获取外部事件并订阅它,也可以调用外部对象并传递“this”或对其中一个字段的引用。有很多种方式可以让一个对象最终得到其他对象的引用!您只能通过代码检查进行检查-检查表单中的所有方法,并确保它没有订阅外部对象,也没有将“this”引用传递给任何可能挂起引用的外部对象。(希望你明白我的意思。)@Nick:还有一件事:在我们的工作中,有一个14天的免费试用期,所以你可以用它来检查。这对于发现像这样的“漏洞”是非常好的——但它确实有一点学习曲线。无论如何都要考虑。