views:

341

answers:

3

I've recently noticed some behaviour with the Visual Studio Designer (C#) that I don't understand and was wondering if someone could clarify...

One some of my Windows Forms, the first line of the designer generated code reads;

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

When this is the case, the dispose method, in that same designer file, the dispose method places two "Dispose" calls within the case "if" condition as follows;

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

i.e. Nothing is called unless disposing is true, AND components is not null.

On some other forms, that first line in the designer generated code is missing. In these cases the base.Dispose call is outside the "if" condition as such...

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

I have noticed this while tracking down a bug with a form not closing, where this.components was null, yet the base.Dispose call was inside that condition (I suspect the designer code had been tampered with but that's another story.

What controls this behaviour?

(Some earlier forms in the project were created in VS 2005 and we now use VS 2008 - clue?)

+1  A: 

Interesting glitch! It does indeed sound like a bug in one version of the designer / templating. Of course, if you think the designer code had been tampered, all bets are pretty-much off anyway...

However, in VS2008, it generates the undoubtably correct version:

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

So the base Dispose(...) is called. I haven't got VS2005 handy to test it, unfortunately. However - it doesn't initialize the components until it has to - the declaration is:

private System.ComponentModel.IContainer components = null;

And then if it is needed, it is populated in InitializeComponent:

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

I guess with this construct it only has to maintain InitializeComponent (and not the fields itself).

Marc Gravell
No me either Marc. I'll have to give it a try at home tonight. Thanks.
Stuart Helwig
A: 

I have seen this happen, and I've also occasionally got warnings about from the Dispose method about components either never having its value assigned, or not being defined.

I think it is a combination of two things:

  1. Slightly different code generation between versions of Visual Studio
  2. The Dispose method is only generated if there is not one already in the file, whereas InitializeComponent (and associated declarations) is generated each time

This results in an InitializeComponent/declarations section that is out-of-whack with the Dispose method.

Ch00k
+1  A: 

This is reproducible behavior. When you create a new form, it starts out with a skeleton that includes the this.components constructor call. When you then add a component (say a Timer) and remove it again, the designer regenerates the code, now without the constructor call. That isn't a bug.

Fwiw, the skeleton code is generated by Common7\IDE\CSharp\ItemsTemplates\1033\Form.zip\form.designer.cs

Seeing the base.Dispose() call inside the if() statement is a bug. That might be self-induced. Or it might be a beta version of the skeleton code. VS2005 does it right. Do check the ItemsTemplatesCache folder.

Hans Passant
Thanks nobugz. I have had a chance to try this scenario in VS2005 now too. It's fine. I can only assume, as you say, this was "self induced".
Stuart Helwig