在c#中使用按钮后,我是否必须取消订阅按钮事件

本文关键字:按钮 取消 事件 是否 | 更新日期: 2023-09-27 18:03:30

我使用的是windows窗体。

我的C#应用程序包含100个user controls。我在需要的时候一次显示/隐藏这100个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订阅了该事件,但在应用程序的使用过程中从未使用过它们。

我在这里和这里读到了一些关于取消订阅事件的内容,但有些答案说你应该取消订阅,因为这会导致内存泄漏,有些答案说不必,因此答案仍然不清楚。

我的问题是,使用button事件后是否必须取消订阅,例如:当我显示/隐藏user control时。如果是,当显示user control时如何订阅button事件,当未显示时如何取消订阅。

在c#中使用按钮后,我是否必须取消订阅按钮事件

为什么取消订阅

它归结为订阅者(UserControl(与订阅(Button(相比的使用寿命。订阅包含对订阅服务器的引用。因此,如果订阅的使用寿命更长,那么订阅的内存就会泄漏给订阅。

因此,在您的情况下,您应该询问按钮是否会比UserControl持续更长时间。如果按钮的使用寿命较短,则无需取消订阅。否则,您将内存泄漏UserControl。

在你的情况下,我想你不需要取消订阅。

如果我答对了你的问题-每个控件只订阅它自己的子控件(30个按钮(。当忘记取消订阅是个坏主意时,发布者(按钮(的寿命将比订阅者(用户控件(长。为什么?因为发布者将存储到订阅服务器的链接,并将阻止该订阅服务器被垃圾回收器处理在您的情况下,按钮的寿命永远不会超过它的父用户控件,所以您不需要取消订阅

在您的情况下,没有理由担心。你链接到的两个例子有一个不同的"种类"事件,如下所示:如果对象a发生了变化,那么应该调用方法X,这样X就可以对对象a中的变化进行操作或处理。例如,A=产品的库存;如果A的计数为零,那么它就不能再出售,或者必须订购新的物品,等等。

当响应更改的数据时,调用X的需求可能会在某个时间点停止,然后注销事件可能会很有益,尤其是在没有其他方法中断或禁用链接的情况下。

然而,在像您这样的用户界面场景中,通常仍然需要调用X。如果需要,可以通过另一种方式控制它,例如禁用按钮或隐藏按钮。在按钮和方法之间建立链接确实没有什么代价。断开链接的唯一原因是"如果点击按钮,我不想再叫X了"。

您通常不必取消订阅事件。也就是说,在特殊情况下,需要这样做。

这通常看起来是这样的:您有一个长寿命对象,它创建长寿命对象并附加它们的方法来处理其(或其他一些长寿命对象的(事件。或者,可以创建一个对象,并将其方法附加到寿命更长的不同对象的事件。

现在,当这些短寿命对象超出范围时,它们仍然会附加到事件,因此只要长寿命对象(它们订阅到的事件(在范围内,Garbage Collector就不会回收它们。这是因为它保留了它们对应该处理其事件的对象的引用。

在您的情况下(以及大多数其他典型情况下(,处理程序是拥有子控件的类的成员,因此不存在人为延长任何对象的生存期的风险。您不需要在此处明确取消订阅。

您实际上不必取消订阅,但您应该取消订阅。取消订阅的方式是:

//adding
EventHandler myHandler = new EventHandler(MyButtonClick);
button1.Click += myHandler;
//removing
button1.Click -= myHandler;