我正在使用Windows窗体。
我的C#应用程序包含100 user controls
。当我需要并隐藏其余部分时,我会显示/隐藏其中一个user controls
。
这些user controls
中的每一个都有30个buttons
,我在构造函数中订阅button
事件,如下所示:
public UserControl1()
{
InitializeComponent();
button1.Click += new EventHandler(MyButtonClick);
button2.Click += new EventHandler(MyButtonClick);
.
.
button30.Click += new EventHandler(MyButtonClick);
}
void MyButtonClick(object sender, EventArgs e)
{
// do something
}
因此,当我运行应用程序时,所有100 User controls
订阅了30 buttons
事件,而某些user controls
订阅了该事件,但它们在使用期间从不使用应用
我读过一些关于取消订阅事件here和Here的内容,但有些答案说你应该取消订阅,因为它会导致内存泄漏,而有些人说你没必要,因此答案仍然不明确。
我的问题是,在使用它之后我必须取消订阅button
事件,例如:当我显示/隐藏user control
时。如果是,我如何在显示button
时订阅user control
事件,并在未显示时取消订阅。
答案 0 :(得分:10)
为什么要取消订阅?
与订阅(Button)相比,它归结为订阅者(UserControl)的生命周期。订阅持有对订户的引用。因此,如果订阅具有更长的生命周期,那么订阅者将使内存泄漏订阅者。
因此,在您的情况下,您应该询问按钮是否会比UserControl持续更长时间。如果Buttons在相同的生命周期内缩短,则无需取消订阅。否则你将内存泄漏UserControl。
在您的情况下,我猜您不需要取消订阅。
答案 1 :(得分:1)
如果我的问题是正确的 - 每个控制仅订阅IT' S OWN儿童(30个按钮)。忘记取消订阅的情况不好主意是发布者(按钮)的寿命比订阅者(用户控制)长。为什么?因为发布者将存储指向订阅者的链接,并将阻止该订阅者被垃圾收集器处理。 在您的情况下,按钮永远不会超过其父级用户控制,因此您不需要取消订阅。
答案 2 :(得分:1)
您通常不会 取消订阅活动。也就是说,在需要时会有例外情况。
这通常如下所示:您有一个长期存在的对象,它创建短期对象并附加其方法来处理其(或其他一些长期存在的对象)事件。或者,您可以创建一个对象并将其方法附加到具有更长生命周期的不同对象的事件。
现在,当这些短期对象超出范围时,它们仍将附加到事件中,因此Garbage Collector
只要长期存在的对象(他们订阅了它们的事件)就不会回收它们)在范围内。这是因为它保留了对应该处理其事件的对象的引用。
在您的情况下(以及大多数其他典型的处理程序),处理程序是拥有子控件的类的成员,因此不存在人为延长任何对象生命的风险。您无需在此明确取消订阅。
答案 3 :(得分:1)
在您的情况下,没有理由担心。您链接的两个示例有不同的类型'事件,如下所示:如果对象A发生更改,则应调用方法X,因此X可以处理或处理对象A中的更改。 例如A =产品库存;如果A的数量变为零,则无法再出售,或者必须订购新商品等。
当响应已更改的数据时,调用X的需要可能在某个时间点停止存在,然后取消注册该事件可能是有益的,尤其是在没有其他方法来中断或禁用链接时。
但是在诸如你的用户界面场景中,调用X的需要通常会保持不变。如果需要,可以用另一种方式控制,例如,通过禁用按钮或隐藏它。在按钮和方法之间建立链接确实没什么代价的。打破链接的唯一原因是“如果点击按钮,我不再希望X被称为EVER。”
答案 4 :(得分:-1)
你并不是必须取消订阅,但你应该这样做。取消订阅的方式是:
//adding
EventHandler myHandler = new EventHandler(MyButtonClick);
button1.Click += myHandler;
//removing
button1.Click -= myHandler;