【问题标题】:Do you have to ubsubscribe from Disposed? [duplicate]您必须取消订阅 Disposed 吗? [复制]
【发布时间】:2019-11-13 17:40:30
【问题描述】:

我听说您应该取消订阅已释放控件上的事件。

TextBox textBox;
void Initialize()
{
    textBox = new TextBox();
    textBox.Click += ClickHandler;

    this.Disposed += DisposeControl;
}

void ClickHandler(object sender, EventArgs e)
{
    this.foo = bar;
}

void DisposeControl(object sender, EventArgs e)
{
    textBox.Click -= ClickHandler;
    this.Disposed -= DisposeControl; // DOES THIS LINE MAKE SENSE?
}

在释放后没有对控件的引用,所以我认为没有必要取消注册任何事件处理程序。然而,正如我提到的,人们说你应该这样做。这是否包括注销 dispose 事件本身?

【问题讨论】:

  • 我发现有道理。但我认为它没有用,因为 Disposed 应该只被调用一次。
  • 您可以在这里查看相关性:Component.Dispose
  • @Peter Duniho 请不要链接到四个通常相关的问题,并说我的问题是重复的。这是这样工作的吗?您只需在 Google 上搜索四个半相关的问题,如果该问题听起来一定在过去某个时间点已经回答过,就称其为重复问题?这四个问题中的任何一个都没有解决我的确切问题。
  • 我同意我认为 SO 的“重复关闭”过程有点激进。我发现,当您遇到问题时,并不总是很容易看到相似之处。在这种情况下,虽然@PeterDuniho 链接到的文章没有以您提出的确切方式回答您的问题,但它们确实回答了您的一般问题。上面的第四个是我在回答中链接到的那个。我的答案的唯一区别是我在您的示例和其他答案中表达的内容之间“连接了点”。

标签: c# winforms


【解决方案1】:

要回答您的问题“这条线有意义吗?”,在您的示例中它没有。那是因为事件源和目标都是相同的。我将稍微重写你的代码。

class SOTest1 : Control
{
    private bool bar = true;
    private bool foo { get; set; }

    TextBox textBox;
    void Initialize()
    {
        textBox = new TextBox();
        textBox.Click += ClickHandler;

        this.Disposed += DisposeControl;
    }

    void ClickHandler(object sender, EventArgs e)
    {
        this.foo = bar;
    }

    void DisposeControl(object sender, EventArgs e)
    {
        textBox.Click -= ClickHandler;
        this.Disposed -= DisposeControl; // DOES THIS LINE MAKE SENSE?
    }
}

在这种情况下,由于Control 实现了IDisposable,它在处理结束时调用Disposed 事件,因此带有事件的对象和事件处理程序都是同一个对象。因此,C# 垃圾收集器将看到对象和所有引用已被释放,并将其全部清除。

此外,由于textBox 及其事件处理程序包含在该对象中,因此textBox.Click -= ClickHandler 也是多余的,因为在释放 SOTest1 对象时,它们都会被 GC 清除。

清理事件订阅者不是一个坏习惯,但是它确实添加了很多时候不必要的代码。当您的代码使用完资源后,C# 可以很好地清理资源。

在某些情况下可能会发生内存泄漏,例如带有处理程序的对象的生命周期比带有事件的对象的生命周期短。本文的主要答案有一个很好的例子:What best practices for cleaning up event handler references?

【讨论】:

    【解决方案2】:

    我更喜欢使用 IDisposable 来处理这种情况

    List<IDisposable> eventsToDispose = new List<IDisposable>();
    
    eventsToDispose.Add(Disposable.Create(() => 
    {
         textBox.Click += ClickHandler;
    }));
    

    然后你就可以dispose handler了

    eventsToDispose.ForEach(o => o.Dispose());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-27
      • 2018-09-26
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 2017-06-09
      • 2019-01-31
      • 1970-01-01
      相关资源
      最近更新 更多