【问题标题】:Why does the WinForms designer generate somewhat 'inconvenient' code in its dispose method?为什么 WinForms 设计器会在其 dispose 方法中生成一些“不方便”的代码?
【发布时间】:2012-01-09 19:35:29
【问题描述】:

当您创建表单或用户控件时,WinForms 设计器会生成如下所示的 dispose 方法:

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

此代码的问题在于,如果曾经对其进行编辑以处置其他对象,它可能会导致不正确的行为。我见过带有 dispose 方法的 .designer.cs 文件,如下所示:

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
            if (_myDisposable != null)
                _myDisposable.Dispose();
            if (_myOtherDisposable != null)
                _myOtherDisposable.Dispose();
        }
        base.Dispose(disposing);
    }

...这是不正确的,因为 _myDisposable 和 _myOtherDisposable 的处置不应该取决于组件是否为空。

因此,忽略关于编辑此设计器生成的代码是否是一种好习惯的论点,并忽略您可以通过编辑模板来更改它的事实,我的问题是:为什么设计器不生成代码看起来更像这样?

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if(components != null)
                components.Dispose();
        }
        base.Dispose(disposing);
    }

此代码具有相同的最终结果,但更安全,并且在修改过程中不易出错。

【问题讨论】:

  • 第一个和第三个代码块(几乎)相同。还是我错过了什么?
  • @Erno - 你是对的,因为&& 会短路。
  • 所以没有问题(勺子)?
  • 只有 disposing 为 true 且 components 不为 null 时才会进入第一个代码块中的 if 语句,这意味着如果 components 为 null,则不会执行您放入其中的任何其他内容。当 disposing 为真时,将输入第三块中的 if 语句,因此在其中放入其他内容是安全的。
  • 按原样,这些块是等效的。但是如果你想通过把它放在 if() 语句中来处理额外的东西,它们的行为会有所不同。

标签: c# winforms visual-studio


【解决方案1】:

答案是:因为在 Microsoft 编写此功能的人并不是最关心您的方便。或者他们认为你作为一个非微软员工,不可能成为一名优秀的程序员,因此,你应该远离有风险的业务,比如修改对象的 Dispose() 方法。

顺便说一下,Dispose() 方法位于 .Designer.cs 文件中指定为“不要编辑此设计器生成的代码”的区域之外,所以我想可以编辑它。

【讨论】:

    【解决方案2】:

    我认为这是因为微软的“官方”IDisposable 模式试图适应太多的情况,这是不必要的。

    有关更多详细信息,请参阅 Stephen Cleary 撰写的这篇出色的文章:[关于 IDisposable 的事情你母亲从未告诉过你]https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About)。他对IDisposable 的问题以及如何解决这些问题有一些深刻的见解。

    Stephen 提供了一个简单的指导方针:不要在一个类中混合托管和非托管资源;相反,将每个非托管资源包装在一个 IDisposable 类中,其唯一目的是处置非托管资源。

    如果遵循此准则,则不再需要这种神秘的 Dispose 方法,同时可以解决一大堆其他更严重的问题,使用 Microsoft 推荐的模式。

    【讨论】:

    • +1。即便如此,在将它们包装在 IDisposable 中之后,仍然需要在使用完它们后调用Dispose(),无论是显式地还是通过using ( ) { }。否则,这种行为并不比完全不包装它们好多少。
    【解决方案3】:

    处理表单上包含的资源的处置的推荐方法是使用 FormClosing 或 FormClosed 事件。 UserControl 有一个用于相同目的的 Disposed 事件。

    【讨论】:

    • Closing 和 Closed 都已过时,在 .NET 2.0 中被 FormClosing 和 FormClosed 取代。您在哪里找到该建议?
    • @Hans,我已经相应地编辑了回复;几年前我被口头告知要使用 Closing/Closed,但我忘记了它们实际上被命名为 FormClosing 和 FormClosed。我实际上并不知道有其他名称的过时事件。
    【解决方案4】:

    你是对的,你甚至没有提到它放在 Designer.cs 文件中的事实。

    您必须先将其移动(到 MyForm.cs),然后对其进行编辑。有一些常识...

    但这在很大程度上是学术性的,components==null 只会在完全空的表单上为真。放下 1 个按钮或标签,问题不会出现。

    我刚刚检查过,即使在空表单上也不是null。 (好吧,显然只适用于 Fx 4+)

    【讨论】:

    • Components 在 VS 2010 中似乎永远不会为空,但在 VS 2008 及更低版本中,除非您专门在表单中添加诸如计时器之类的组件,否则它将始终为空。
    猜你喜欢
    • 2018-04-11
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多