【问题标题】:Why does the Visual Studio IDE sometimes initialize the "this.components object: and other times not?为什么 Visual Studio IDE 有时会初始化“this.components 对象:而其他时候不会?
【发布时间】:2009-02-17 04:24:47
【问题描述】:

我最近注意到 Visual Studio Designer (C#) 的一些行为,我不理解,想知道是否有人可以澄清...

我的一些Windows Forms,设计器生成的第一行代码如下;

this.components = new System.ComponentModel.Container();

在这种情况下,dispose 方法在同一个设计器文件中,dispose 方法将两个“Dispose”调用置于 case“if”条件中,如下所示;

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

即除非 disposing 为 true,并且组件不为 null,否则不会调用任何内容。

在其他一些表单中,缺少设计器生成的代码中的第一行。在这些情况下,base.Dispose 调用在“if”条件之外......

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

我在跟踪表单未关闭的错误时注意到了这一点,其中 this.components 为空,但 base.Dispose 调用在该条件内(我怀疑设计器代码已被篡改,但这是另一回事。

是什么控制了这种行为?

(项目中的一些早期表单是在 VS 2005 中创建的,我们现在使用 VS 2008 - 线索?)

【问题讨论】:

    标签: c# visual-studio winforms visual-studio-2008 visual-studio-2005


    【解决方案1】:

    这是可重现的行为。当您创建一个新表单时,它会从一个包含 this.components 构造函数调用的骨架开始。然后,当您添加一个组件(例如 Timer)并再次删除它时,设计器会重新生成代码,现在无需调用构造函数。这不是错误。

    Fwiw,骨架代码由Common7\IDE\ItemTemplates\CSharp\Windows Forms\1033\Form.zip\form.designer.cs生成

    在 if() 语句中看到 base.Dispose() 调用是一个错误。那可能是自作自受。或者它可能是骨架代码的测试版。 VS2005 做得对。请检查 ItemsTemplatesCache 文件夹。

    【讨论】:

    • 感谢 nobugz。我现在也有机会在 VS2005 中尝试这种情况。没关系。正如你所说,我只能假设这是“自我诱导的”。
    • “现在没有构造函数调用”。那么,(components != null) 检查是否在任何地方都没有components 初始化有什么意义呢?谁,何时何地初始化components?顺便说一句,从VS2010来到这里,.NET4.0
    • 您似乎有一个新问题。您可以通过单击按钮来询问它。
    • @HansPassant 所以我们不应该担心它,因为 GC 释放了例如计时器?
    【解决方案2】:

    6年后,这个问题仍然存在。我已经设法找到它发生的至少一个原因。

    在测试您的组件是否具有采用 IContainer 的构造函数时,System.ComponentModel.Design.Serialization.ComponentCodeDomSerializer 会为您的项目缓存对 IContainer 类型的引用。如果您随后在同一个解决方案中为另一个项目保存了一个对象,或者当您在项目中进行了一些其他类型的更改时,ComponentCodeDomSerializer 将无法再找到构造函数,因为 IContainer 的类型不再等于它的缓存类型。

    如果您的项目经常发生这种情况,那么有一个非常难看的解决方法。将此 VBC# VisualStudioWorkaroundSerializer 类添加到您的解决方案中。然后将属性DesignerSerializer(GetType(VisualStudioWorkaroundSerializer), GetType(CodeDomSerializer)) 添加到您的组件中。无论何时保存您的组件,此自定义序列化程序都会检测到问题并进行修复,并在此问题即将发生时强制您再次保存。

    【讨论】:

      【解决方案3】:

      有趣的故障!它确实听起来像一个版本的设计器/模板中的错误。当然,如果您认为设计器代码已被篡改,那么无论如何,所有的赌注都差不多......

      但是,在 VS2008 中,它生成的版本无疑是正确的:

      if (disposing && (components != null))
      {
          components.Dispose();
      }
      base.Dispose(disposing);
      

      所以基础Dispose(...) 被调用。不幸的是,我没有方便的 VS2005 来测试它。但是 - 它不会初始化组件,直到它必须 - 声明是:

      private System.ComponentModel.IContainer components = null;
      

      然后如果需要的话,填入InitializeComponent:

      private void InitializeComponent()
      {
          this.components = new System.ComponentModel.Container();
          //...
      }
      

      我猜这个结构只需要维护InitializeComponent(而不是字段本身)。

      【讨论】:

      • 马克也没有我。今晚我得在家里试一试。谢谢。
      • “如果你认为设计器代码被篡改了”——是我,因为我不知道如何修改它!
      【解决方案4】:

      我已经看到了这种情况,并且我偶尔也会从 Dispose 方法中收到有关组件的警告,即组件要么从未被赋值,要么未被定义。

      我认为这是两件事的结合:

      1. Visual Studio 版本之间的代码生成略有不同
      2. 仅当文件中还没有 Dispose 方法时才会生成,而 InitializeComponent(和相关的声明)每次都会生成

      这会导致 InitializeComponent/declarations 部分与 Dispose 方法不一致。

      【讨论】:

      • “Visual Studio 版本之间” - 来自于在 VS2010、.NET4.0 中创建全新的 Windows 窗体应用程序而不使用任何其他版本(尽管 UI 已在 PC 上安装了 VS2008)
      猜你喜欢
      • 2016-10-19
      • 1970-01-01
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2012-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多