Forms collection behavior

C

craig

In order to be able to track some of the forms in my application, I am using
a collection of forms (I am using an ArrayList per the Billy Hollis MSDN
Article
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet05132003.asp )
.. As I instantiate each new forms, I add a reference to the new form to the
collection. My question is - what happens to each of these references as
the forms are closed by the user?

As I cycle through all of the forms in the collection, I notice that
references to closed forms still exist in the collection, but their
IsDisposed property is set to true. Is it safe to use the IsDisposed
property as an indicator that the form has been closed by the user? What
happens to the reference in the collection when garbage collection blows
away the form? Do I have to manually remove disposed forms from the
collection?

Also, is it OK to add additional code to the Dispose method of a form to
release resources that the form was using?

Thanks!
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi craig,

I haven't look on Billy Hollis' code. Anyways if you close the form it
disposes itself. That means it releases any unmanaged resource it uses. The
istance of the form class, though, is still alive as a normal alive object
in the managed heap and it will be alive until there are references to the
object. You obvously keep at least one in the collection. You can not use
anything of the form that may involve polling the underlying windows control
or use anything from the form that uses unmanaged resources, but you can use
any other method, property or data member. Once again GC won't tuch your
form until you keep references to it.

Checking IsDisposed is the right thing you to do. You may cosider checking
Disposing as well. because if form is in process of disposing itself you
cannot use it. This might happen in multithread invironment or in some verry
rear cases when the diposing is done as part of the finaliziation of the
form.

Yes, you can add more code to the Dispose method. Bare in mind that form
will take care of all componets and controls you put in the form with the
designer and you should dispose only your unamnaged resources that the form
doesn't know about.
Just a reminder. you don't have to do anything with managed resources in the
dispose method you should take care only for unmanaged ones. For example
don't use Dispose to null references your form keeps or unhook events your
form uses. It will be taken care of for you

--
B\rgds
100
craig said:
In order to be able to track some of the forms in my application, I am using
a collection of forms (I am using an ArrayList per the Billy Hollis MSDN
Article
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet05132003.asp )
 
C

craig

Thanks for taking the time to give me such a thorough answer to my question.
I appreciate it.

I make use of a custom data-binding scheme to bind my business objects to my
forms. Though I have made modifications, I adopted the scheme from some
work done by another developer. That developer implemented IDisposable in
all of his custom data-binding classes in order to nullify all references
and unhook events within the classes. Therefore, I did the same thing in
some of the additional classes I wrote. Apparently, none of this work was
necessary. Its nice to know that I won't have to continue to do that.

Once again, thanks!


Stoitcho Goutsev (100) said:
Hi craig,

I haven't look on Billy Hollis' code. Anyways if you close the form it
disposes itself. That means it releases any unmanaged resource it uses. The
istance of the form class, though, is still alive as a normal alive object
in the managed heap and it will be alive until there are references to the
object. You obvously keep at least one in the collection. You can not use
anything of the form that may involve polling the underlying windows control
or use anything from the form that uses unmanaged resources, but you can use
any other method, property or data member. Once again GC won't tuch your
form until you keep references to it.

Checking IsDisposed is the right thing you to do. You may cosider checking
Disposing as well. because if form is in process of disposing itself you
cannot use it. This might happen in multithread invironment or in some verry
rear cases when the diposing is done as part of the finaliziation of the
form.

Yes, you can add more code to the Dispose method. Bare in mind that form
will take care of all componets and controls you put in the form with the
designer and you should dispose only your unamnaged resources that the form
doesn't know about.
Just a reminder. you don't have to do anything with managed resources in the
dispose method you should take care only for unmanaged ones. For example
don't use Dispose to null references your form keeps or unhook events your
form uses. It will be taken care of for you
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht
ml/vbnet05132003.asp )
 
S

Saurabh

You may also override OnClosing( ) and just hide the form instead of
disposing it, make sure you cancel the event, and then dispose the form when
you are done with it. I would recommend this method if you want to close and
re-create the form frequently.

--Saurabh
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi,
Just to clarify one point. You cannot recreate disposed form.
I believe it is not what you meant.
 
S

Saurabh

I do something like this :
protected override void OnClosing(CancelEventArgs e)

{

e.Cancel = true;

base.OnClosing (e);

Hide();

}

which means for the user, the form is gone, but I still keep it as it is,
and the next time user wants it, i just call show on the existing form. I
hope this is alright.

Thanks,

--Saurabh
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Yes, you can do that as long as an event handler of the Closing event
doesn't set the Cancel flag to false.
If you want to prevent that you should call first the base.Closing (which
will raise the event) and then e.Cancel = true.

Anyways, the programmer using the form should be fully aware of that. If
s/he doesn't know that you hide the form instead of closing it s/he won't
simply call Show. The user will create a fresh new instance of the form and
the old one will be left for GC for finalization (which will dispose it).
Which is unnecessary holding of unmanaged resources.
 
C

craig

In my case, my main form has a list of customers and the a double click on
any of the customers brings up a form that allows them to edit all of the
customer details. The user needs to have the ability to open multiple
customers at the same time, so I can't simple recycle the same form over and
over (hide and show), which means I need to close each form after it is
used.
 
C

craig

I wanted to double check on this one more time before I start deleting all
of my Dispose() code. Are you sure that there is no benefit to code in the
Dispose methods of objects that releases all references to managed objects
and unhooks events? If there is no benefit to this, I will blow away all of
the Dispose() code I have written, but if there is anything to be gained by
leaving it in there, I might as well do that!

Any thoughts? Thanks!
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Craig,

Once you cut off all references to the form all object that your form
references are going to be garbage collected along with the form as long as
there is no other references outside the form to them. In the latter case
you don't want dispose them anyways. Unlike COM there is no reference
counter inside the objects. When GC starts collecting the garbage it
dynamically builds a graph of referenced objects and objects which are not
included in that graph are potential garbage. Nulling the references won't
speed up the process.
For more info how GC works refer to MSDN
http://msdn.microsoft.com/msdnmag/issues/1100/gci/
http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/

For the same reason you don't have to unhook any events you form has hooked.
But you have to unhook all events provided by the form and hooked by objects
outside the form. Otherwise those events handlers are references to the form
and the form (and all objects referenced by it) won't be collected. Anyway
this shouldn't be responsibility of the form.
If you have any doubts refer to the articles I gave you. I'm sure you will
find the answers of your questions there.
 
C

craig

I do have a custom data-binding object that handles events that are raised
by controls on my form. However, the only reference to that custom
data-binding object is held by the form itself. I think that in a case like
that, I don't have to unhook the event handlers, because when the form is
destroyed, the custom data binding object is destroyed along with it.
Correct?

Also, as I mentioned earlier, I have a forms collection that is holding
references to all of the forms the user opens. As the user closes those
forms, the IsDisposed properties of the forms becomes set to true.
Periodically, I need to examine the forms collection and remove forms for
which IsDisposed is set to true so that the GC can release their resources.
What is the best way to cycle through a collection and remove members that
meet a certain condition? I don't think I can use a foreach or for
construct because each time I remove a member of the collection, the
collection changes and the construct counter goes out of sync.

I could just restart the cycle each time I find and remove a collection
member for which IsDisposed is true until I finally make it through the
entire collection. Would that be the best approach?

Thanks for all the input!!!
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi craig,

craig said:
I do have a custom data-binding object that handles events that are raised
by controls on my form. However, the only reference to that custom
data-binding object is held by the form itself. I think that in a case like
that, I don't have to unhook the event handlers, because when the form is
destroyed, the custom data binding object is destroyed along with it.
Correct?

Actually that is a HUGE mistake. I've shouldn't say that. Sorry. Where was
my head when I wrote that?!
It is the other way arround. You have to unhook all events you form has
hooked, but you don't have to do that for internal objects that will be
garbage collected along with the form (most of the cases). But if the form
has hooked an event of an object which is going to be alive longer than the
form you have to onhook them. Otherwise they will keep the form alive. Once
again the event provider collects the delegate objects which are the
references that's why the form as a subscriber have to unhook those events.

Anyways, I believe, the place of those unhookings is not in the Dispose
method. Because if the Dispose is not call explicitly and is left for the GC
and the class finalizer. That object will stay alive as long as the event
provider. Why? Because the delegate (event) is keeping reference to the form
and GC won't consider it for finalization. With forms you are kind of safe
because the are automatically disposed when are closed, but it may be (and
it is ) not the case with other objects. So, keep Dispose for releasing
unmanaged resources.
However you don't have to do this unhooking in your case because haw you
said the objects are held by the form and not referenced form anywhere
Also, as I mentioned earlier, I have a forms collection that is holding
references to all of the forms the user opens. As the user closes those
forms, the IsDisposed properties of the forms becomes set to true.
Periodically, I need to examine the forms collection and remove forms for
which IsDisposed is set to true so that the GC can release their
resources.

IsDisposed == true means that the resources has been already released. The
form is usless as a UI control. However the Form object is alive on the heap
and you can use all non UI properties (usually those are your own data
properties)
In your case you have to remove the form from the collection in order to be
removed from the memory (some times when GC decides so)
What is the best way to cycle through a collection and remove members that
meet a certain condition? I don't think I can use a foreach or for
construct because each time I remove a member of the collection, the
collection changes and the construct counter goes out of sync.

1. No, you can't use enumerator returned by collections' GetEnumerator()
method. *foreach* loop uses that enumerator so you cannot used it as well.
Ofcourse you can write your own enumerator that can make it possible.
Refere to this aricle for how to write such an enumerator object
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp01212002.asp

2. You do can use *for* and *while* loops as long as that collection of
yours support indexing and you maintain properly the index. For example:
int index = 0
while(index < col.Count)
{
if(((Control)col[index]).IsDisposed) col.RemoveAt[index];
else index++;
}

You can use *for* loop in a similar manner.

3. If the collection doesn't support indexing you can clone the collection
and loop through the copy and remove the items from the original. This, BTW,
is how the the enumerator in 1.) works. Then you can leave the copy of the
collection and it will be collected by GC along with the forms

Assuming the collection implements ICollection (just to make the things
easier)

ArrayList temp = new ArrayList(col);
foreach(Control ctrl in copy)
{
col.Remove(ctrl);
}

As long as temp is local variable for some method you don't have to set
temp = null because it will become unreferenced as soon as the variable goes
out of scope. In reality the temp collection will be eligible for GC even
before the end of the scope of the variable (as soon as no code uses that
variable).

4. You can hook all forms Closed event. You should use the same event
handler for all of them in the as a responce of the event you can remove the
form form the collection.

private void aForm_Closed(object sender, EventArgs e)
{
col.Remove(sender);
}

This is what I suggest.
I could just restart the cycle each time I find and remove a collection
member for which IsDisposed is true until I finally make it through the
entire collection. Would that be the best approach?

Thanks for all the input!!!

Yes, you can do that if you don't like the other solutions.

--
HTH
B\rgds
100>
Stoitcho Goutsev (100) said:
Craig,

Once you cut off all references to the form all object that your form
references are going to be garbage collected along with the form as long as
there is no other references outside the form to them. In the latter case
you don't want dispose them anyways. Unlike COM there is no reference
counter inside the objects. When GC starts collecting the garbage it
dynamically builds a graph of referenced objects and objects which are not
included in that graph are potential garbage. Nulling the references won't
speed up the process.
For more info how GC works refer to MSDN
http://msdn.microsoft.com/msdnmag/issues/1100/gci/
http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/

For the same reason you don't have to unhook any events you form has hooked.
But you have to unhook all events provided by the form and hooked by objects
outside the form. Otherwise those events handlers are references to the form
and the form (and all objects referenced by it) won't be collected. Anyway
this shouldn't be responsibility of the form.
If you have any doubts refer to the articles I gave you. I'm sure you will
find the answers of your questions there.

--
HTH
B\rgds
100

in
the all gained
by this
work but
you finaliziation
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht of
 
C

craig

Wow.....you gave me quite a bit to chew on in that last message.

While I was waiting to hear how you would approach doing something like
this, I wrote the following routine that removes all closed forms from the
_consumerEditForms collection. It does so by searching through the
collection until it finds a form with IsDisposed == true. It then removes
that form from the collection and then restarts the search from the
beginning of the collection. It repeats this process until it makes it all
the way through the collection without finding any closed forms.

private void RemoveClosedForms()
{
//Remove closed Consumer Edit forms
FormConsumerEdit formConsumerEdit;
Boolean restart = false;
Int32 count;

do
{
restart = false;
count = _consumerEditForms.Count;
for(int i=0;i<=count-1;i++)
{
formConsumerEdit = (FormConsumerEdit)_consumerEditForms;
if(formConsumerEdit.IsDisposed == true)
{
_consumerEditForms.Remove(formConsumerEdit);
if(i == (count-1))
{
restart = false;
}
else
{
restart = true;
}
break;
}
}
} while (restart == true);
}

I am going to take some time to explore the other options that you mentioned
in order to see if they might be more efficient.

Also, what do you think of the this idea: As each edit form is instantated
by the main form, the main form could hook into the Closed event of the new
edit form. It could then handle this event by removing the form from the
form collection. Do you think that would be a better solution?

I can't tell you how much I have enjoyed discussing this with you. I am
learning quite a bit about the logistics of using Windows Forms. You seem
to be a VERY experienced developer. How long have you been working with
..NET?

Thanks!
craig


Stoitcho Goutsev (100) said:
Hi craig,

craig said:
I do have a custom data-binding object that handles events that are raised
by controls on my form. However, the only reference to that custom
data-binding object is held by the form itself. I think that in a case like
that, I don't have to unhook the event handlers, because when the form is
destroyed, the custom data binding object is destroyed along with it.
Correct? the
form

Actually that is a HUGE mistake. I've shouldn't say that. Sorry. Where was
my head when I wrote that?!
It is the other way arround. You have to unhook all events you form has
hooked, but you don't have to do that for internal objects that will be
garbage collected along with the form (most of the cases). But if the form
has hooked an event of an object which is going to be alive longer than the
form you have to onhook them. Otherwise they will keep the form alive. Once
again the event provider collects the delegate objects which are the
references that's why the form as a subscriber have to unhook those events.

Anyways, I believe, the place of those unhookings is not in the Dispose
method. Because if the Dispose is not call explicitly and is left for the GC
and the class finalizer. That object will stay alive as long as the event
provider. Why? Because the delegate (event) is keeping reference to the form
and GC won't consider it for finalization. With forms you are kind of safe
because the are automatically disposed when are closed, but it may be (and
it is ) not the case with other objects. So, keep Dispose for releasing
unmanaged resources.
However you don't have to do this unhooking in your case because haw you
said the objects are held by the form and not referenced form anywhere
Also, as I mentioned earlier, I have a forms collection that is holding
references to all of the forms the user opens. As the user closes those
forms, the IsDisposed properties of the forms becomes set to true.
Periodically, I need to examine the forms collection and remove forms for
which IsDisposed is set to true so that the GC can release their
resources.

IsDisposed == true means that the resources has been already released. The
form is usless as a UI control. However the Form object is alive on the heap
and you can use all non UI properties (usually those are your own data
properties)
In your case you have to remove the form from the collection in order to be
removed from the memory (some times when GC decides so)
What is the best way to cycle through a collection and remove members that
meet a certain condition? I don't think I can use a foreach or for
construct because each time I remove a member of the collection, the
collection changes and the construct counter goes out of sync.

1. No, you can't use enumerator returned by collections' GetEnumerator()
method. *foreach* loop uses that enumerator so you cannot used it as well.
Ofcourse you can write your own enumerator that can make it possible.
Refere to this aricle for how to write such an enumerator object
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp01212002.asp

2. You do can use *for* and *while* loops as long as that collection of
yours support indexing and you maintain properly the index. For example:
int index = 0
while(index < col.Count)
{
if(((Control)col[index]).IsDisposed) col.RemoveAt[index];
else index++;
}

You can use *for* loop in a similar manner.

3. If the collection doesn't support indexing you can clone the collection
and loop through the copy and remove the items from the original. This, BTW,
is how the the enumerator in 1.) works. Then you can leave the copy of the
collection and it will be collected by GC along with the forms

Assuming the collection implements ICollection (just to make the things
easier)

ArrayList temp = new ArrayList(col);
foreach(Control ctrl in copy)
{
col.Remove(ctrl);
}

As long as temp is local variable for some method you don't have to set
temp = null because it will become unreferenced as soon as the variable goes
out of scope. In reality the temp collection will be eligible for GC even
before the end of the scope of the variable (as soon as no code uses that
variable).

4. You can hook all forms Closed event. You should use the same event
handler for all of them in the as a responce of the event you can remove the
form form the collection.

private void aForm_Closed(object sender, EventArgs e)
{
col.Remove(sender);
}

This is what I suggest.
I could just restart the cycle each time I find and remove a collection
member for which IsDisposed is true until I finally make it through the
entire collection. Would that be the best approach?

Thanks for all the input!!!

Yes, you can do that if you don't like the other solutions.

--
HTH
B\rgds
100>
long
as the
form deleting
all away
all
instead
to
my resource
it You
can or
in resources
that
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht
the
new forms
from
method
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi Craig,
I am going to take some time to explore the other options that you mentioned
in order to see if they might be more efficient.
I'm afraid that this is quite unefficient you make a lot of unncessary
passes.

Take a look at the solutions I gave you. They do that in one pass.
Also, what do you think of the this idea: As each edit form is instantated
by the main form, the main form could hook into the Closed event of the new
edit form. It could then handle this event by removing the form from the
form collection. Do you think that would be a better solution?

That's my 4.) solution :) . How I said recommend it.
I can't tell you how much I have enjoyed discussing this with you. I am
learning quite a bit about the logistics of using Windows Forms. You seem
to be a VERY experienced developer. How long have you been working with
.NET?

Thank you very much :) I'm flattered. I could say quite long (as long such a
thing could be said when it goes for .NET :)).

Thanks!
craig


Stoitcho Goutsev (100) said:
Hi craig,

case
like


Actually that is a HUGE mistake. I've shouldn't say that. Sorry. Where was
my head when I wrote that?!
It is the other way arround. You have to unhook all events you form has
hooked, but you don't have to do that for internal objects that will be
garbage collected along with the form (most of the cases). But if the form
has hooked an event of an object which is going to be alive longer than the
form you have to onhook them. Otherwise they will keep the form alive. Once
again the event provider collects the delegate objects which are the
references that's why the form as a subscriber have to unhook those events.

Anyways, I believe, the place of those unhookings is not in the Dispose
method. Because if the Dispose is not call explicitly and is left for
the
GC
and the class finalizer. That object will stay alive as long as the event
provider. Why? Because the delegate (event) is keeping reference to the form
and GC won't consider it for finalization. With forms you are kind of safe
because the are automatically disposed when are closed, but it may be (and
it is ) not the case with other objects. So, keep Dispose for releasing
unmanaged resources.
However you don't have to do this unhooking in your case because haw you
said the objects are held by the form and not referenced form anywhere

resources.

IsDisposed == true means that the resources has been already released. The
form is usless as a UI control. However the Form object is alive on the heap
and you can use all non UI properties (usually those are your own data
properties)
In your case you have to remove the form from the collection in order to be
removed from the memory (some times when GC decides so)


1. No, you can't use enumerator returned by collections' GetEnumerator()
method. *foreach* loop uses that enumerator so you cannot used it as well.
Ofcourse you can write your own enumerator that can make it possible.
Refere to this aricle for how to write such an enumerator object
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp01212002.asp
2. You do can use *for* and *while* loops as long as that collection of
yours support indexing and you maintain properly the index. For example:
int index = 0
while(index < col.Count)
{
if(((Control)col[index]).IsDisposed) col.RemoveAt[index];
else index++;
}

You can use *for* loop in a similar manner.

3. If the collection doesn't support indexing you can clone the collection
and loop through the copy and remove the items from the original. This, BTW,
is how the the enumerator in 1.) works. Then you can leave the copy of the
collection and it will be collected by GC along with the forms

Assuming the collection implements ICollection (just to make the things
easier)

ArrayList temp = new ArrayList(col);
foreach(Control ctrl in copy)
{
col.Remove(ctrl);
}

As long as temp is local variable for some method you don't have to set
temp = null because it will become unreferenced as soon as the variable goes
out of scope. In reality the temp collection will be eligible for GC even
before the end of the scope of the variable (as soon as no code uses that
variable).

4. You can hook all forms Closed event. You should use the same event
handler for all of them in the as a responce of the event you can remove the
form form the collection.

private void aForm_Closed(object sender, EventArgs e)
{
col.Remove(sender);
}

This is what I suggest.
I could just restart the cycle each time I find and remove a collection
member for which IsDisposed is true until I finally make it through the
entire collection. Would that be the best approach?

Thanks for all the input!!!

Yes, you can do that if you don't like the other solutions.

--
HTH
B\rgds
100>
Craig,

Once you cut off all references to the form all object that your form
references are going to be garbage collected along with the form as long
as
there is no other references outside the form to them. In the latter case
you don't want dispose them anyways. Unlike COM there is no reference
counter inside the objects. When GC starts collecting the garbage it
dynamically builds a graph of referenced objects and objects which
are
not
included in that graph are potential garbage. Nulling the references won't
speed up the process.
For more info how GC works refer to MSDN
http://msdn.microsoft.com/msdnmag/issues/1100/gci/
http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/

For the same reason you don't have to unhook any events you form has
hooked.
But you have to unhook all events provided by the form and hooked by
objects
outside the form. Otherwise those events handlers are references to the
form
and the form (and all objects referenced by it) won't be collected. Anyway
this shouldn't be responsibility of the form.
If you have any doubts refer to the articles I gave you. I'm sure
you
will
find the answers of your questions there.

--
HTH
B\rgds
100

I wanted to double check on this one more time before I start deleting
all
of my Dispose() code. Are you sure that there is no benefit to
code
in
the
Dispose methods of objects that releases all references to managed
objects
and unhooks events? If there is no benefit to this, I will blow away
all
of
the Dispose() code I have written, but if there is anything to be gained
by
leaving it in there, I might as well do that!

Any thoughts? Thanks!



Hi,
Just to clarify one point. You cannot recreate disposed form.
I believe it is not what you meant.
instead
of
disposing it, make sure you cancel the event, and then dispose the
form
when
you are done with it. I would recommend this method if you
want
to
do resources,
but
invironment
or the
form ones.
For
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht
collection,
but by
the method
 
C

craig

Yes! You did recomment this. I hadn't read all of the options before I
replied to you.

I agree that this is the way to go. Initially, I wrote the event handler as
follows:

private void formConsumerEdit_Closed(object sender, EventArgs e)
{
//Release all references to formConsumerEdit after it it closed by the
//user so that the GC can reclaim formConsumerEdit resources.
FormConsumerEdit form = (FormConsumerEdit)sender;
form.Closed -= new EventHandler(formConsumerEdit_Closed);
_consumerEditForms.Remove(form);
}

However, if I understand you correctly, you are saying that I don't need to
unhook the event in this event handler because the delegate that maintains
the reference to the handler is in the form that is being disposed. Thus, I
can simplify this code to:

private void formConsumerEdit_Closed(object sender, EventArgs e)
{
//Release all references to formConsumerEdit after it it closed by the
//user so that the GC can reclaim formConsumerEdit resources.
FormConsumerEdit form = (FormConsumerEdit)sender;
_consumerEditForms.Remove(form);
}

Once this handler executes, my main form will no longer have any references
to the consumer edit form, thus the GC will be able to reclaim the resources
used by the consumer edit form. Am I correct?

I guess this means that as developers, we need to be very careful about
managing the references between our objects so that GC can clean up
properly. Mistakes might be costly.


Stoitcho Goutsev (100) said:
Hi Craig,
I am going to take some time to explore the other options that you mentioned
in order to see if they might be more efficient.
I'm afraid that this is quite unefficient you make a lot of unncessary
passes.

Take a look at the solutions I gave you. They do that in one pass.
Also, what do you think of the this idea: As each edit form is instantated
by the main form, the main form could hook into the Closed event of the new
edit form. It could then handle this event by removing the form from the
form collection. Do you think that would be a better solution?

That's my 4.) solution :) . How I said recommend it.
I can't tell you how much I have enjoyed discussing this with you. I am
learning quite a bit about the logistics of using Windows Forms. You seem
to be a VERY experienced developer. How long have you been working with
.NET?

Thank you very much :) I'm flattered. I could say quite long (as long such a
thing could be said when it goes for .NET :)).

Thanks!
craig


form
is to
the than
the the the
form forms
for the
heap to
be members
that
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp01212002.asp
2. You do can use *for* and *while* loops as long as that collection of
yours support indexing and you maintain properly the index. For example:
int index = 0
while(index < col.Count)
{
if(((Control)col[index]).IsDisposed) col.RemoveAt[index];
else index++;
}

You can use *for* loop in a similar manner.

3. If the collection doesn't support indexing you can clone the collection
and loop through the copy and remove the items from the original.
This,
BTW,
is how the the enumerator in 1.) works. Then you can leave the copy of the
collection and it will be collected by GC along with the forms

Assuming the collection implements ICollection (just to make the things
easier)

ArrayList temp = new ArrayList(col);
foreach(Control ctrl in copy)
{
col.Remove(ctrl);
}

As long as temp is local variable for some method you don't have to set
temp = null because it will become unreferenced as soon as the
variable
goes
out of scope. In reality the temp collection will be eligible for GC even
before the end of the scope of the variable (as soon as no code uses that
variable).

4. You can hook all forms Closed event. You should use the same event
handler for all of them in the as a responce of the event you can
remove
the
form form the collection.

private void aForm_Closed(object sender, EventArgs e)
{
col.Remove(sender);
}

This is what I suggest.

I could just restart the cycle each time I find and remove a collection
member for which IsDisposed is true until I finally make it through the
entire collection. Would that be the best approach?

Thanks for all the input!!!

Yes, you can do that if you don't like the other solutions.

--
HTH
B\rgds
100>

Craig,

Once you cut off all references to the form all object that your form
references are going to be garbage collected along with the form
as
long
as
there is no other references outside the form to them. In the latter
case
you don't want dispose them anyways. Unlike COM there is no reference
counter inside the objects. When GC starts collecting the garbage it
dynamically builds a graph of referenced objects and objects which are
not
included in that graph are potential garbage. Nulling the references
won't
speed up the process.
For more info how GC works refer to MSDN
http://msdn.microsoft.com/msdnmag/issues/1100/gci/
http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/

For the same reason you don't have to unhook any events you form has
hooked.
But you have to unhook all events provided by the form and hooked by
objects
outside the form. Otherwise those events handlers are references
to
the
form
and the form (and all objects referenced by it) won't be collected.
Anyway
this shouldn't be responsibility of the form.
If you have any doubts refer to the articles I gave you. I'm sure you
will
find the answers of your questions there.

--
HTH
B\rgds
100

I wanted to double check on this one more time before I start deleting
all
of my Dispose() code. Are you sure that there is no benefit to code
in
the
Dispose methods of objects that releases all references to managed
objects
and unhooks events? If there is no benefit to this, I will blow away
all
of
the Dispose() code I have written, but if there is anything to be
gained
by
leaving it in there, I might as well do that!

Any thoughts? Thanks!



Hi,
Just to clarify one point. You cannot recreate disposed form.
I believe it is not what you meant.

--
B\rgds
100
You may also override OnClosing( ) and just hide the form instead
of
disposing it, make sure you cancel the event, and then
dispose
the
form
when
you are done with it. I would recommend this method if you
want
to
close
and
re-create the form frequently.

--Saurabh

Thanks for taking the time to give me such a thorough
answer
to
my
question.
I appreciate it.

I make use of a custom data-binding scheme to bind my business
objects
to
my
forms. Though I have made modifications, I adopted the scheme
from
some
work done by another developer. That developer implemented
IDisposable
in
all of his custom data-binding classes in order to nullify all
references
and unhook events within the classes. Therefore, I did
the
same
thing
in
some of the additional classes I wrote. Apparently, none of
this
work
was
necessary. Its nice to know that I won't have to continue
to
do
that.

Once again, thanks!


Hi craig,

I haven't look on Billy Hollis' code. Anyways if you
close
the
form
it
disposes itself. That means it releases any unmanaged resource
it
uses.
The
istance of the form class, though, is still alive as a normal
alive
object
in the managed heap and it will be alive until there are
references
to
the
object. You obvously keep at least one in the
collection.
You
can
not
use
anything of the form that may involve polling the underlying
windows
control
or use anything from the form that uses unmanaged resources,
but
you
can
use
any other method, property or data member. Once again GC won't
tuch
your
form until you keep references to it.

Checking IsDisposed is the right thing you to do. You may
cosider
checking
Disposing as well. because if form is in process of disposing
itself
you
cannot use it. This might happen in multithread
invironment
or
in
some
verry
rear cases when the diposing is done as part of the
finaliziation
of
the
form.

Yes, you can add more code to the Dispose method. Bare
in
mind
that
form
will take care of all componets and controls you put in the
form
with
the
designer and you should dispose only your unamnaged resources
that
the
form
doesn't know about.
Just a reminder. you don't have to do anything with managed
resources
in
the
dispose method you should take care only for unmanaged ones.
For
example
don't use Dispose to null references your form keeps or
unhook
events
your
form uses. It will be taken care of for you

--
B\rgds
100
In order to be able to track some of the forms in my
application,
I
am
using
a collection of forms (I am using an ArrayList per the Billy
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi craig,
I agree that this is the way to go. Initially, I wrote the event handler as
follows:

private void formConsumerEdit_Closed(object sender, EventArgs e)
{
//Release all references to formConsumerEdit after it it closed by the
//user so that the GC can reclaim formConsumerEdit resources.
FormConsumerEdit form = (FormConsumerEdit)sender;
form.Closed -= new EventHandler(formConsumerEdit_Closed);
_consumerEditForms.Remove(form);
}

However, if I understand you correctly, you are saying that I don't need to
unhook the event in this event handler because the delegate that maintains
the reference to the handler is in the form that is being disposed. Thus, I
can simplify this code to:

Yes, you got it right :) you DON'T need to unhook that event.
And if you don't use strongly typed collection (as ArrayList) you don't have
to cast the reference as well
But I suppose you do use strongly typed collection and you have to do the
casting.
Once this handler executes, my main form will no longer have any references
to the consumer edit form, thus the GC will be able to reclaim the resources
used by the consumer edit form. Am I correct?

You are completely right as long as you don't have any other references to
the form.
I guess this means that as developers, we need to be very careful about
managing the references between our objects so that GC can clean up
properly. Mistakes might be costly.

Yes, there are some things that are not so obvious. GC is a good thing, but
we still need to know how it works.

Stoitcho Goutsev (100) said:
Hi Craig,

I'm afraid that this is quite unefficient you make a lot of unncessary
passes.

Take a look at the solutions I gave you. They do that in one pass. the
new

That's my 4.) solution :) . How I said recommend it.


Thank you very much :) I'm flattered. I could say quite long (as long
such
a
thing could be said when it goes for .NET :)).
hooked
by Where
was the
form for
the of
safe be
(and released.
The
order
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp01212002.asp
2. You do can use *for* and *while* loops as long as that collection of
yours support indexing and you maintain properly the index. For example:
int index = 0
while(index < col.Count)
{
if(((Control)col[index]).IsDisposed) col.RemoveAt[index];
else index++;
}

You can use *for* loop in a similar manner.

3. If the collection doesn't support indexing you can clone the collection
and loop through the copy and remove the items from the original. This,
BTW,
is how the the enumerator in 1.) works. Then you can leave the copy
of
the
collection and it will be collected by GC along with the forms

Assuming the collection implements ICollection (just to make the things
easier)

ArrayList temp = new ArrayList(col);
foreach(Control ctrl in copy)
{
col.Remove(ctrl);
}

As long as temp is local variable for some method you don't have to set
temp = null because it will become unreferenced as soon as the variable
goes
out of scope. In reality the temp collection will be eligible for GC even
before the end of the scope of the variable (as soon as no code uses that
variable).

4. You can hook all forms Closed event. You should use the same event
handler for all of them in the as a responce of the event you can remove
the
form form the collection.

private void aForm_Closed(object sender, EventArgs e)
{
col.Remove(sender);
}

This is what I suggest.

I could just restart the cycle each time I find and remove a collection
member for which IsDisposed is true until I finally make it
through
the
entire collection. Would that be the best approach?

Thanks for all the input!!!

Yes, you can do that if you don't like the other solutions.

--
HTH
B\rgds
100>

Craig,

Once you cut off all references to the form all object that your form
references are going to be garbage collected along with the form as
long
as
there is no other references outside the form to them. In the latter
case
you don't want dispose them anyways. Unlike COM there is no reference
counter inside the objects. When GC starts collecting the
garbage
it which
are
hooked
by sure
you to
code nullify
all
none
of continue
to in
the
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht reference
collection,
I use
the closed
by
 
C

craig

Thanks for being so willing to help me out. I can't tell you how much I
appreciate it. I have learned alot from you.

If I ever get stuck again...you will be the guy I look for!!!! :)


Stoitcho Goutsev (100) said:
Hi craig,
I agree that this is the way to go. Initially, I wrote the event
handler
as
follows:

private void formConsumerEdit_Closed(object sender, EventArgs e)
{
//Release all references to formConsumerEdit after it it closed by the
//user so that the GC can reclaim formConsumerEdit resources.
FormConsumerEdit form = (FormConsumerEdit)sender;
form.Closed -= new EventHandler(formConsumerEdit_Closed);
_consumerEditForms.Remove(form);
}

However, if I understand you correctly, you are saying that I don't need to
unhook the event in this event handler because the delegate that maintains
the reference to the handler is in the form that is being disposed.
Thus,
I
can simplify this code to:

Yes, you got it right :) you DON'T need to unhook that event.
And if you don't use strongly typed collection (as ArrayList) you don't have
to cast the reference as well
But I suppose you do use strongly typed collection and you have to do the
casting.
Once this handler executes, my main form will no longer have any references
to the consumer edit form, thus the GC will be able to reclaim the resources
used by the consumer edit form. Am I correct?

You are completely right as long as you don't have any other references to
the form.
I guess this means that as developers, we need to be very careful about
managing the references between our objects so that GC can clean up
properly. Mistakes might be costly.

Yes, there are some things that are not so obvious. GC is a good thing, but
we still need to know how it works.

I
am You
seem such the
form with
it. form
has hooked references
to form
has will
be to
the haw
you on
the order
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp01212002.asp
2. You do can use *for* and *while* loops as long as that
collection
of
yours support indexing and you maintain properly the index. For example:
int index = 0
while(index < col.Count)
{
if(((Control)col[index]).IsDisposed) col.RemoveAt[index];
else index++;
}

You can use *for* loop in a similar manner.

3. If the collection doesn't support indexing you can clone the
collection
and loop through the copy and remove the items from the original. This,
BTW,
is how the the enumerator in 1.) works. Then you can leave the
copy
of to
set form
as garbage form
has hooked references
to to
be did
the none
again
GC You
may Bare
in
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht
reference collection,
 

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