为什么Visual Studio IDE有时会初始化“this.components对象:有时候不会?

时间:2009-02-17 04:24:47

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

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

我的一些Windows窗体,设计器的第一行生成代码读取;

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

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

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

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

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

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

我已经注意到这一点,同时跟踪一个没有关闭的表单的bug,其中this.components为null,但base.Dispose调用是在那个条件内(我怀疑设计师代码已被篡改但这是另一个故事。

什么控制了这种行为?

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

4 个答案:

答案 0 :(得分:4)

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

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

生成

在if()语句中查看base.Dispose()调用是一个错误。这可能是自我诱导的。或者它可能是骨架代码的beta版本。 VS2005做对了。检查ItemsTemplatesCache文件夹。

答案 1 :(得分:3)

6年后,这个问题仍然存在。我设法找到了至少一个原因。

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

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

答案 2 :(得分:1)

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

但是,在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(而不是字段本身)。

答案 3 :(得分:0)

我已经看到这种情况发生了,我偶尔也会从Dispose方法中得到有关组件的警告,这些组件要么从未分配过值,要么没有定义。

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

  1. Visual Studio版本之间的代码生成略有不同
  2. 只有在文件中没有已经存在的情况下才会生成Dispose方法,而每次都会生成InitializeComponent(及相关的声明)
  3. 这会导致InitializeComponent / declarations部分与Dispose方法不同。