Why does my destructor never run?
Solution 1
Only one of the three ways to implement a destructor that you list actually involves a destructor, and that's ~Destructor()
.
If you implement IDisposable
, and dispose of your object, then the code in Dispose
will run, but there's no reason to think that your destructor will.
I think you chasing the impossible here. Destructors run as and when the garbage collector so decrees. It's not something that you have any control over. The GC is well within its rights to form the opinion that running destructors simply wastes time, and if there is plenty of memory it will form that opinion.
If you need predictable disposal, finalization etc., then use IDisposable
.
Solution 2
Unless you are studying garbage collection, a destructor is not the place for your tracing. You should look at Dispose (which is overridable in Form). This occurs after the unmanaged resource (like your window handle) has been released.
protected override void Dispose(bool disposing)
{
System.Diagnostics.Trace.WriteLine(
"Form1.Dispose " + (disposing ? "disposing " : "")
+ this.GetHashCode().ToString());
base.Dispose (disposing);
}
If you want to see if a form/control has been disposed, use the Control.IsDisposed
property.
Edit: Because of GC.SuppressFinalize
, your Finalize method (destructor syntax in C#) will never execute if Dispose is called explicitly (or by the framework).
For more information, see Implementing a Dispose Method.
Solution 3
Add a FormClosed event to the designer.
ie:
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(Form1_FormClosed);
Then create the appropriate function to handle the event.
Solution 4
Yes, you should probably give up on the idea of a destructor, because they're non-deterministic by nature. I'm not sure why you need to have the form disposed as opposed to just closed, but simply closing it should be enough in most cases.
You could use IDisposable
but that depends on why you need the form to be garbage collected. If you need to re-use it, just create another instance.
Solution 5
The Form gets garbage collected when no references exist and the garbage collector happens to run. You can force the garbage collector by calling GC.Collect(). You should not reference any other object within a Finalizer (aka destructor) because the object might have been garbage collected already.
You can use memory analyzer tools to find out whether your object is garbage collected or not, if you really need to.
You also have to keep in mind that the finalizer is called from a thread other than the main thread.
EDIT: If your problem is just that you don't see the trace output, you might have to turn autoflush on
<configuration>
<system.diagnostics>
<trace autoflush="true" />
</system.diagnostics>
</configuration>
EDIT 2: There might be an external reference to your form, such as a registered event handler. I would suggest that you add a button in an administration area of your application which executes the following code:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Like this the garbage collector must run and should destroy your form (set a breakpoint into the finalizer). If not, you have some reference to the object which has to be destroyed.
Jeson Martajaya
Updated on April 04, 2020Comments
-
Jeson Martajaya about 4 years
I have a blank Winform with a destructor method
public partial class Form1 : Form { public Form1() { System.Diagnostics.Trace.WriteLine("Form1.Initialize " + this.GetHashCode().ToString()); InitializeComponent(); } ~Form1() { System.Diagnostics.Trace.WriteLine("Form1.Dispose " + this.GetHashCode().ToString()); } }
When the form is destroyed, I want it to write to the output window:
(Form1 opened) Form1.Initialize 41149443 (Form1 closed) Form1.Dispose 41149443
MSDN suggests 3 ways in implementing destructor:
~Destructor() http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
IDisposable http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
SafeHandle pattern http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx
However, none of these ways write "Form1.Dispose 41149443" to the output Window. Therefore, I am not able to tell whether the form has been destroyed or not. Suggestions ?
Should I give up hope on achieving this due to uncertainty of garbage collector?
Is there another way to know whether Form1 has been garbage collected ? -
apacay over 12 years@agent-j shouldn't that be
"Form1.Dispose " + (disposing ? "disposing " : "")
-
slfan over 12 yearsIDisposable is not automatically predictable, you have to call Dispose or use using(). And how would you call Dispose()?
-
David Heffernan over 12 years@slfan What are you talking about?
Dispose
runs when it is called, invariably viausing
. Where did I say thatDispose
would run automatically? -
agent-j over 12 years@slfan, my point is that this is called by the finalizer only if necessary. If someone disposes the form explicitly, the destructor (finilize method) likely never is executed because of GC.SupressFinalize. See the Dispose pattern for more info.
-
slfan over 12 years@agent-j: You're right, I haven't seen that Dispose() with the bool parameter is actually implemented in the Form class. Therefore your Dispose will be called from the finalizer or from the base method. But you should ALWAYS call base.Dispose(disposing); when you override this method.
-
slfan over 12 yearsYou wrote "if you need predictable disposal...". If you don't use using or call it explicitly, it's not called. As I have never used using with a form, it's even less predictable than the finalizer.
-
David Heffernan over 12 years@slfan
IDisposable
exists to provide predictable disposal. What else is it for?! Should you so desire to implement it on a form, and useusing
, then theDispose
method would run at a predictable point. I didn't say it was a good idea to do that. What I did say was "If you implementIDisposable
, and dispose of your object, then the code inDispose
will run". -
LoganS over 12 years@slfan - I don't think he meant it that way.
-
Jeson Martajaya over 12 yearsI understand what you mean: 1) It is impossible to have a predictable destructor. 2) It is possible to have predictable IDisposable with using. More in blog.dmbcllc.com/2008/11/10/dispose-with-using
-
David Heffernan over 12 yearsas @slfan says, IDisposable is not typically used on a form.
-
slfan over 12 yearsOk, try my 2nd guess. Maybe you have some references to the form.
-
slfan over 12 yearsYes, and it does NOT call the finalizer either! That's why I would not call it a predictable disposal. It's just a standard pattern to work with unmanaged resources and any class that has a finalizer should implement the IDisposable pattern. But in my opinion this answer is not a reply to the question above.
-
David Heffernan over 12 years@slfan I even say in the answer that the finalizer won't run.
-
gmail user over 10 yearsI tried the 2nd option and it worked. I think yours is most closest answer compares to others.
-
Hi-Angel over 9 yearsHm… I am wonder, are destructors in C# have a mean at all? Usually it is used to free some resources, close file descriptors (e.g. I am tried to close socket here), but since here no a hint about the time the destructor called, it is impossible to use it as usual.
-
Thick_propheT about 9 yearsFor one,
Form
s already implement IDisposable. Secondly, if theForm
is the mainForm
for the app, just wrap it in ausing
statement inProgram.cs
.