Dispose(bool), Idisposable, form closing etc.

R

rbrowning1958

Hello,

I am confused by dispose etc. and hope someone can set me right.

1. The Dispose(Bool) the IDE generates for a form has nothing to do
with IDisposable, right?
2. So when is this called? When a form is closed? If this is caused
automatically when a form is closed how can I then access things on a
modal from after ShowDialog() returns? Or is it only for modeless
forms?
3. Does the garbage collector automically call Dispose() which is part
of IDisposable when an onbject is garbage collected? I know this is
non-deterministic etc. Is this what is known as the Finalizer or
whatever it's called?
4. I don't understand how garbage collection works with forms. If I
have a method which declares a variable which is a form, and
instantiate it in the same routine, when I leave the routine the
variable is released, the form's reference count should then be zero
and therefore a candiate for garbage collection, no? Is there another
refernce to it somewhere?

Confused,

Ray
 
P

Peter Duniho

Hello,

I am confused by dispose etc. and hope someone can set me right.

1. The Dispose(Bool) the IDE generates for a form has nothing to do
with IDisposable, right?

I wouldn't go that far. It's not part of the interface, but it is part
of the common implementation of the interface.
2. So when is this called? When a form is closed? If this is caused
automatically when a form is closed how can I then access things on a
modal from after ShowDialog() returns? Or is it only for modeless
forms?

Forms shown with ShowDialog() are not disposed when they are closed.
3. Does the garbage collector automically call Dispose() which is part
of IDisposable when an onbject is garbage collected? I know this is
non-deterministic etc. Is this what is known as the Finalizer or
whatever it's called?

If you have not called Dispose(), then the finalizer won't be
suppressed and the finalizer may eventually be called. The object
cannot be collected until the finalizer is run (for objects that have a
finalizer and don't suppress finalizing).
4. I don't understand how garbage collection works with forms.

It works the same as for other classes that implement IDisposable.
If I
have a method which declares a variable which is a form, and
instantiate it in the same routine, when I leave the routine the
variable is released, the form's reference count should then be zero
and therefore a candiate for garbage collection, no? Is there another
refernce to it somewhere?

There's no referencing counting.

As far as eligibility for garbage collection goes, what matters is
where there's a reference to the form somewhere else. In the case of a
form, its instance is added to the application's list of open forms,
which you can retrieve from the Application.OpenForms property.

So, yes...there's still a reference to the form somewhere.

Pete
 
N

Nicholas Paldino [.NET/C# MVP]

Ray,

See inline:
1. The Dispose(Bool) the IDE generates for a form has nothing to do
with IDisposable, right?

Well, in a roundabout way, it does. The implementation of the Dispose
method on the form class Form will call the override that is defined in your
subclass (the Dispose(bool) implementation).
2. So when is this called? When a form is closed? If this is caused
automatically when a form is closed how can I then access things on a
modal from after ShowDialog() returns? Or is it only for modeless
forms?

It is called when a form is closed and it is not a modal form, yes.
When showing the form modally, it doesn't dispose the form until Dispose is
called on it (if you click the X button, it doesn't dispose yet, it just
hides it). From the documentation from the ShowDialog method:
When a form is displayed as a modal dialog box, clicking the Close button
(the button with an X at the upper-right corner of the form) causes the form
to be hidden and the DialogResult property to be set to DialogResult.Cancel.
Unlike modeless forms, the Close method is not called by the .NET Framework
when the user clicks the close form button of a dialog box or sets the value
of the DialogResult property. Instead the form is hidden and can be shown
again without creating a new instance of the dialog box. Because a form
displayed as a dialog box is not closed, you must call the Dispose method of
the form when the form is no longer needed by your application.

In this case, you would do something like this:

using (MyForm myForm = new MyForm())
{
// Show it.
if (myForm.ShowDialog() = <whatever you want to compare to>)
...

}
3. Does the garbage collector automically call Dispose() which is part
of IDisposable when an onbject is garbage collected? I know this is
non-deterministic etc. Is this what is known as the Finalizer or
whatever it's called?


Well, if Dispose is not called on the form (directly or indirectly) then
when the form has no more references to it, and it is garbage collected,
Dispose is called.
4. I don't understand how garbage collection works with forms. If I
have a method which declares a variable which is a form, and
instantiate it in the same routine, when I leave the routine the
variable is released, the form's reference count should then be zero
and therefore a candiate for garbage collection, no? Is there another
refernce to it somewhere?

There is no actual reference count, per se, but all the reference to the
form are gone, so yes, it is a candidate for GC. This assumes you didn't
pass the reference outside of the method, or assigned it to some field
elsewhere which is keeping the object alive.
 
B

Brian Gideon

Hello,

I am confused by dispose etc. and hope someone can set me right.

1. The Dispose(Bool) the IDE generates for a form has nothing to do
with IDisposable, right?

Well, it is related because that is required for the canonical
implemenation of IDisposable. But, you are correct. There is no
strict relationship between Dispose(bool) and IDisposable.
2. So when is this called? When a form is closed? If this is caused
automatically when a form is closed how can I then access things on a
modal from after ShowDialog() returns? Or is it only for modeless
forms?

It is called when either the IDisposable.Dispose method is called from
user code or as a last resort by the GC when Finalize is called. It's
been awhile, but I don't think closing a modal form disposes it.
Furtheremore, some (most?) class authors choose to allow property
getters to return even after the object has been disposed.
3. Does the garbage collector automically call Dispose() which is part
of IDisposable when an onbject is garbage collected? I know this is
non-deterministic etc. Is this what is known as the Finalizer or
whatever it's called?

The GC will not call IDisposable.Dispose. However, it may indirectly
call Dispose(bool) because it's part of the Finalize method
(destructor in C#)...at least if you've choosen the canonical
implementation of IDisposable.
4. I don't understand how garbage collection works with forms. If I
have a method which declares a variable which is a form, and
instantiate it in the same routine, when I leave the routine the
variable is released, the form's reference count should then be zero
and therefore a candiate for garbage collection, no? Is there another
refernce to it somewhere?

No, there is no reference counting involved. Assuming the form
doesn't somehow register itself in a static data structure then it
should be a candidate for garbage collection once it falls out of
scope.
 
R

rbrowning1958

Ray,

See inline:
1. TheDispose(Bool) the IDE generates for a form has nothing to do
with IDisposable, right?

Well, in a roundabout way, it does. The implementation of theDispose
method on the form class Form will call the override that is defined in your
subclass (theDispose(bool) implementation).
2. So when is this called? When a form is closed? If this is caused
automatically when a form is closed how can I then access things on a
modal from after ShowDialog() returns? Or is it only for modeless
forms?

It is called when a form is closed and it is not a modal form, yes.
When showing the form modally, it doesn'tdisposethe form untilDisposeis
called on it (if you click the X button, it doesn'tdisposeyet, it just
hides it). From the documentation from the ShowDialog method:
When a form is displayed as a modal dialog box, clicking the Close button
(the button with an X at the upper-right corner of the form) causes the form
to be hidden and the DialogResult property to be set to DialogResult.Cancel.
Unlike modeless forms, the Close method is not called by the .NET Framework
when the user clicks the close form button of a dialog box or sets the value
of the DialogResult property. Instead the form is hidden and can be shown
again without creating a new instance of the dialog box. Because a form
displayed as a dialog box is not closed, you must call theDisposemethod of
the form when the form is no longer needed by your application.

In this case, you would do something like this:

using (MyForm myForm = new MyForm())
{
// Show it.
if (myForm.ShowDialog() = <whatever you want to compare to>)
...

}
3. Does the garbage collector automically callDispose() which is part
of IDisposable when an onbject is garbage collected? I know this is
non-deterministic etc. Is this what is known as the Finalizer or
whatever it's called?

Well, ifDisposeis not called on the form (directly or indirectly) then
when the form has no more references to it, and it is garbage collected,Disposeis called.
4. I don't understand how garbage collection works with forms. If I
have a method which declares a variable which is a form, and
instantiate it in the same routine, when I leave the routine the
variable is released, the form's reference count should then be zero
and therefore a candiate for garbage collection, no? Is there another
refernce to it somewhere?

There is no actual reference count, per se, but all the reference to the
form are gone, so yes, it is a candidate for GC. This assumes you didn't
pass the reference outside of the method, or assigned it to some field
elsewhere which is keeping the object alive.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)




Confused,
Ray- Hide quoted text -

- Show quoted text -

Thank you all for replying I've arbitrarily chosen yours to reply to,
Nicholas. So let me see if I have this right:

1. Dispose(Bool) as part of a form is not explicitly part of the
IDisposable interface, but the implementation of IDisposable,Dispose
further up the class hierarchy (form I suppose) calls this. This is
waht Brian called the Canonical implementation (I never did understand
what that word meant!).

2, When a modeless form is called, clicking the form's close button,
or calling the close() method calls IDisposable.Dispose which in turn
calls Dispose(bool).

3. If it's a modal form, clicking the close button or calling the
close method just hides the form, and does not call
IDisposable.dispose. Therefore I have to do it myself or use a Using
clause.

4. A form's destructor will call Dispose(bool) although in most cases
it will not do much because it will already have been called by
IDisposable.dispose. SO...I'm guessing that Idisposable calls
dispose(true), whereas the destructor calls Dispose(false)?

5. With regard to garbage collecting - doesn't Peter have it correct
where he says the form is not garbage collected because it is
referenced by application.openForms?

6. Brian mentioned that some class authors write property getters to
return data even after the form has been destroyed - I don't
understand this. Doesn't this mean the property getter has to be
static - and where would it savbe the data? In static class vars? That
implies I only have one instance of the form, right?

Thanks everbody,

Best

Ray
 
N

Nicholas Paldino [.NET/C# MVP]

Ray,

See inline:
Thank you all for replying I've arbitrarily chosen yours to reply to,
Nicholas.

I'm flattered =P
So let me see if I have this right:

1. Dispose(Bool) as part of a form is not explicitly part of the
IDisposable interface, but the implementation of IDisposable,Dispose
further up the class hierarchy (form I suppose) calls this. This is
waht Brian called the Canonical implementation (I never did understand
what that word meant!).
Yep.

2, When a modeless form is called, clicking the form's close button,
or calling the close() method calls IDisposable.Dispose which in turn
calls Dispose(bool).
Yep.

3. If it's a modal form, clicking the close button or calling the
close method just hides the form, and does not call
IDisposable.dispose. Therefore I have to do it myself or use a Using
clause.
Yep.

4. A form's destructor will call Dispose(bool) although in most cases
it will not do much because it will already have been called by
IDisposable.dispose. SO...I'm guessing that Idisposable calls
dispose(true), whereas the destructor calls Dispose(false)?
Yep.

5. With regard to garbage collecting - doesn't Peter have it correct
where he says the form is not garbage collected because it is
referenced by application.openForms?
Yep.

6. Brian mentioned that some class authors write property getters to
return data even after the form has been destroyed - I don't
understand this. Doesn't this mean the property getter has to be
static - and where would it savbe the data? In static class vars? That
implies I only have one instance of the form, right?

No. The properties would be instance, and you would access them off the
form instance before you call Dispose on the form. You ^could^ get away
with accessing the properties after dispose is called, but only if they are
fields that store data that is not dependent on accessing the disposed form
itself.

For example, if you had a text box with text in it, and then you showed
the form modally, if you expose the text in the textbox in a property by
calling the Text property on the textbox, you will get an exception if you
try to access that property after the form is disposed (since the textbox is
disposed of as well). However, if you store the contents of the TextBox in
a string before you dispose of the form, and then access the string in the
property, you won't have a problem, even if the form is disposed.

However, I don't think you should worry about transferring all of your
control values to fields (instead of accessing the values on the controls
from the properties/methods), as it's completely reasonable to expect that
your object won't work once disposed.
 
C

Christof Nordiek

rbrowning1958 said:
6. Brian mentioned that some class authors write property getters to
return data even after the form has been destroyed - I don't
understand this. Doesn't this mean the property getter has to be
static - and where would it savbe the data? In static class vars? That
implies I only have one instance of the form, right?

Dispose does not delete the instance. It only frees, what should not wait
for the GC to be freed. The fields of the instance still live on, until the
instance is collected. So any propertie, that does not depend on the 'open
state' of the form will be accessible. This includes all properties that
simply access fields. But, in case of a form, you can't access f.e. the
controls of the form (or at least, you shouldn't count on).
If the form is destroyed in the sense, that it is collected, than there is
no reference to the instance left (if the GC worked right ;-) ), and so no
member of the instance can be accessed.

Christof
 
M

Michael C

rbrowning1958 said:
5. With regard to garbage collecting - doesn't Peter have it correct
where he says the form is not garbage collected because it is
referenced by application.openForms?

I'm just guessing here but I'd imagine that application.openForms keeps what
is called a weak reference to the form. This means that if all other
references are dropped then the GC can kill the references in openForms.
6. Brian mentioned that some class authors write property getters to
return data even after the form has been destroyed - I don't
understand this. Doesn't this mean the property getter has to be
static - and where would it savbe the data? In static class vars? That
implies I only have one instance of the form, right?

No, they are instance members. Remember the form is only hidden so
everything can be accessed still

Michael
 
P

Peter Duniho

I'm just guessing here but I'd imagine that application.openForms keeps what
is called a weak reference to the form. This means that if all other
references are dropped then the GC can kill the references in openForms.

No, that's not true. If it were, forms applications would be in a
world of hurt. After all, they by default all start out like this:

void Main()
{
...
Application.Run(new Form1());
}

At a minimum, in the Run() method, there'd have to be some strong
reference to the parameter passed in. But more significantly, this
sort of code:

void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();

form2.Show();
}

which is quite common, would never work if what you say is true.

No, I believe that the list that is exposed as Application.OpenForms is
a list of plain old strong references. The application code itself is
not required to maintain a reference, so there must be a strong
reference somewhere else and the underlying list implementing OpenForms
is the most likely source.

Now that VS2008 is out, it's only a matter of time before you can go
look yourself if you don't believe me. :) In the meantime, you could
get Reflector and look at the implementation. I've never tried it
myself, but I'm confident at what I might find should I try. Weak
references just wouldn't do the job.

Pete
 
B

Brian Gideon

1. Dispose(Bool) as part of a form is not explicitly part of the
IDisposable interface, but the implementation of IDisposable,Dispose
further up the class hierarchy (form I suppose) calls this. This is
waht Brian called the Canonical implementation (I never did understand
what that word meant!).

I used the word canonical to mean an authorized, well-established
pattern.
2, When a modeless form is called, clicking the form's close button,
or calling the close() method calls IDisposable.Dispose which in turn
calls Dispose(bool).

3. If it's a modal form, clicking the close button or calling the
close method just hides the form, and does not call
IDisposable.dispose. Therefore I have to do it myself or use a Using
clause.

4. A form's destructor will call Dispose(bool) although in most cases
it will not do much because it will already have been called by
IDisposable.dispose. SO...I'm guessing that Idisposable calls
dispose(true), whereas the destructor calls Dispose(false)?

5. With regard to garbage collecting - doesn't Peter have it correct
where he says the form is not garbage collected because it is
referenced by application.openForms?

6. Brian mentioned that some class authors write property getters to
return data even after the form has been destroyed - I don't
understand this. Doesn't this mean the property getter has to be
static - and where would it savbe the data? In static class vars? That
implies I only have one instance of the form, right?

I don't think I was very clear. What I meant was that you may still
be able to call some property getters without them throwing exceptions
even after Dispose has been called on the object. That's because
property getters are usually nothing more than trivial wrappers around
instance variables.
 
M

Michael C

Peter Duniho said:
No, that's not true. If it were, forms applications would be in a world
of hurt. After all, they by default all start out like this:

void Main()
{
...
Application.Run(new Form1());
}

That wouldn't be a problem because application.Run would keep a reference.
Although you're probably right about everything else. I guess the form must
remove itself from the collection at some point.

Michael
 
P

Peter Duniho

That wouldn't be a problem because application.Run would keep a reference.

How do you know?

I did write that it _could_ keep a reference. But there's no obvious
reason it should. For example, what if it looked something like this:

void Run(Form form)
{
// some code to add the form instance to the open forms list
// past this point, the variable "form" is never used

// then a message pump loop here
while (GetAMessage() != null)
{
// translate the message
// dispatch the message
}
}

(note that I have no idea what the message pump loop actually looks
like...the above should suffice for this purpose though :) )

In the above example, the "form" parameter is no longer considered a
reference to the instance once the message pump loop is entered, the
last use of the variable having been prior to that point.

Yes, you could fix it by adding a GC.KeepAlive(form) at the end of the
method, but that seems sort of silly to do, especially since the issue
would still exist for other code that instantiates a form, shows it,
and then doesn't keep a copy of the reference anywhere.
Although you're probably right about everything else. I guess the form must
remove itself from the collection at some point.

I'm sure that when the form is actually disposed, it removes itself
from the open forms list.

Assuming this is true, it's also a highlight as to why it's so
important to dispose forms shown modally when you're done with them.
For many managed types that implement IDisposable, if you forget to
dispose them eventually it's likely that the finalizer will catch up
and go ahead and do that work for you.

But if a form isn't removed from the open forms list until it's
disposed, and a form isn't eligible for garbage collection until it's
removed from the open forms list, then a modal form that you don't
dispose will _never_ be garbage collected. It's a very serious
resource leak, much more so than the usual "didn't dispose" kind of bug.

Though, I admit I don't really know the details. Now I'm curious, so
if I get a moment I'll actually test it and see if I can figure out
what's going on.

The bottom line, however, is that you do not need to keep a reference
to an open form in order to prevent it from being collected. The
framework is keeping a strong reference itself, ensuring the form
sticks around as long as it needs to.

Pete
 
M

Michael C

Peter Duniho said:
In the above example, the "form" parameter is no longer considered a
reference to the instance once the message pump loop is entered, the last
use of the variable having been prior to that point.

I just gave it a test and the reference remains valid until the function
exists. So unless they actually set it not null (which I doubt) then it
would remain a reference.
The bottom line, however, is that you do not need to keep a reference to
an open form in order to prevent it from being collected. The framework
is keeping a strong reference itself, ensuring the form sticks around as
long as it needs to.

I wonder how it did all this before the forms collection existed.
 
P

Peter Duniho

I just gave it a test and the reference remains valid until the function
exists. So unless they actually set it not null (which I doubt) then it
would remain a reference.

That doesn't tell you anything. As long as the reference is in the
open forms list (and of course it would be), the fact that the
reference remains valid until the function exits is meaningless.

In fact, it's a given that the reference to the form would remain valid
until Application.Run() returns, because if that weren't true a forms
application would never work. By definition, the method returns when
the form is closed, so obviously the duration of the call to
Application.Run() and the lifetime of the form are _very_ closely tied
to each other.

In other words, whatever test you did, all it accomplished was proving
that Application.Run() does in fact work. Which hopefully we all
believed already.
I wonder how it did all this before the forms collection existed.

There's no reason to believe that the collection of forms didn't exist
before. Just because it wasn't exposed to the application itself, that
doesn't mean it wasn't there.

Pete
 
P

Peter Duniho

[...]
Although you're probably right about everything else. I guess the form must
remove itself from the collection at some point.

I'm sure that when the form is actually disposed, it removes itself
from the open forms list.

Assuming this is true, it's also a highlight as to why it's so
important to dispose forms shown modally when you're done with them.
For many managed types that implement IDisposable, if you forget to
dispose them eventually it's likely that the finalizer will catch up
and go ahead and do that work for you.

But if a form isn't removed from the open forms list until it's
disposed, and a form isn't eligible for garbage collection until it's
removed from the open forms list, then a modal form that you don't
dispose will _never_ be garbage collected. It's a very serious
resource leak, much more so than the usual "didn't dispose" kind of bug.

Though, I admit I don't really know the details. Now I'm curious, so
if I get a moment I'll actually test it and see if I can figure out
what's going on.

So, I went ahead and checked this. Turns out, even a modal form is
removed from the open forms list when it's closed, even if not disposed.

So there's no really scary anti-finalizer bug you can create in your
application with Form.ShowDialog(). Which is not to say that you
should ignore the requirement to dispose a modal form when you're done
with it. Just that it's likely to eventually get disposed via the
usual finalizer "back-up" procedure even if you don't dispose it.

Pete
 
M

Michael C

Peter Duniho said:
That doesn't tell you anything. As long as the reference is in the open
forms list (and of course it would be), the fact that the reference
remains valid until the function exits is meaningless.

No, I gave it a test with a regular class. The class would not be collected
until the function exited.
In fact, it's a given that the reference to the form would remain valid
until Application.Run() returns, because if that weren't true a forms
application would never work. By definition, the method returns when the
form is closed, so obviously the duration of the call to Application.Run()
and the lifetime of the form are _very_ closely tied to each other.

I wasn't talking about Application.Run at all. I was just using a regular
function that I defined myself and passed in an instance of a class I
defined. The only way I could get the class to be GCd before the function
exits was to set the parameter to null inside the function.
In other words, whatever test you did, all it accomplished was proving
that Application.Run() does in fact work. Which hopefully we all believed
already.
Rubbish.

There's no reason to believe that the collection of forms didn't exist
before. Just because it wasn't exposed to the application itself, that
doesn't mean it wasn't there.

That's true although that doesn't mean it did exist either.

Michael
 
P

Peter Duniho

No, I gave it a test with a regular class. The class would not be collected
until the function exited.

That's not a test of Application.Run().
I wasn't talking about Application.Run at all. I was just using a regular
function that I defined myself and passed in an instance of a class I
defined. The only way I could get the class to be GCd before the function
exits was to set the parameter to null inside the function.

It is well-known and documented that a reference held only by a
variable that is no longer used is eligible for garbage collection even
while the variable is in scope. It's why GC.KeepAlive() even exists.

If you were unable to reproduce that behavior, it only means your test
was flawed.

You don't believe that Application.Run() does in fact work?
That's true although that doesn't mean it did exist either.

It's easier to believe that it did exist. What is your alternative
theory to explain why even prior to .NET 2.0 you could create a form
instance and have the form remain uncollected even though the only
variable referencing the form goes out of scope?

Pete
 
P

Peter Duniho

[...]
I wasn't talking about Application.Run at all. I was just using a regular
function that I defined myself and passed in an instance of a class I
defined. The only way I could get the class to be GCd before the function
exits was to set the parameter to null inside the function.

It is well-known and documented that a reference held only by a
variable that is no longer used is eligible for garbage collection even
while the variable is in scope. It's why GC.KeepAlive() even exists.

If you were unable to reproduce that behavior, it only means your test
was flawed.

Okay, my apologies on this point.

I still say that unless you look at Application.Run(), you can't really
say for sure what it's doing. It could in fact set the parameter to
null after adding the reference to the list of open forms (by showing
the form). Why it would, I don't know...seems like an odd thing to do,
but then I've seen some seemingly odd code in Windows (though usually
it was only "odd" because I didn't understand the need for it).

However, you're right that parameters are treated differently from
local variables, and as long as the parameter references the instance
for the duration of the call to the method, the instance won't be
collected.

I'm (obviously) a little surprised that parameters aren't treated the
same as local variables. I wonder if there's some subtle difference in
the behavior of a parameter I'm unaware of. At least for parameters
passed by value, I generally view them just like local variables except
that the caller gets to initialize them. But here's one example where
they definitely don't behave like a local variable.

Pete
 
C

Christof Nordiek

Michael C said:
I wasn't talking about Application.Run at all. I was just using a regular
function that I defined myself and passed in an instance of a class I
defined. The only way I could get the class to be GCd before the function
exits was to set the parameter to null inside the function.
How did you test, that the instance was not GC'd?

Was it a debug version? Then the lifetime of the variable wasn't optimized
and extended the whole function, though it may not in an optimized build.

Christof
 
B

Brian Gideon

[snip]

However, you're right that parameters are treated differently from
local variables, and as long as the parameter references the instance
for the duration of the call to the method, the instance won't be
collected.

[snip]

I don't know if I'm convinced of that. You may have been right the
first time. What made you change your mind? Is there a section in
the CLI specification that talks about this?

Obviously, a parameter can be collected during the execution of an
unmanaged function. That's the most important reason for the
existence of GC.KeepAlive. But, I want to know if a parameter can be
collected before the completion of a managed function. I haven't seen
conclusive documentation that guarentees that it won't. In fact, I
don't see any reason why the runtime couldn't support that
optimization. Comments?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top