I know that Destructors in c# do not have an execution order.
The following Structure i do use in several Classes, it's to Desturct instances and the Static Information:
public class MyClass
{
private static readonly Destructor DestructorObject = new Destructor();
~MyClass()
{
Console.WriteLine("Destructor Called");
}
static void Main(string[] args)
{
var myClass = new MyClass();
}
private sealed class Destructor
{
~Destructor()
{
Console.WriteLine("Static Destructor Called");
}
}
}
As I mentioned above the order of Destuctors is undifined. But as im using this construct in many classes I found out, that in each class there is a non changing order, which also remains even if I'm recompiling the application and running it again.
Means that a MyClass1
could alaways run ~MyClass1
first and another class MyClass2
could alawways run ~Destructor
first.
As there clearly is a "hidden" order for each class, can I trust it?
As there clearly is a "hidden" order for each class, can I trust it?
No, you cant. If you look at the the docs, they scream:
The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already been finalized when the finalizer of Object A starts.
Relying on an implementation detail like this as part of you normal flow of execution would be a very bad idea.
Seeing that for some reason you chose to use finalizers as a way of cleaning up static resources, you should first think if that is the right approach, taking into account everything destructors imply, and then at least implement IDisposable
and give the caller a chance to dispose of resources, calling GC.SupressFinalize
as well.
Using this as a common approach in your objects will also cause the objects to prolong their life, as they will be eligible for collection only once they move to the f-reachable queue, and relying on the finalizer thread to actually clean them up, which isn't guaranteed at all.
Eric Lippert has recently (18-05-2015) started a series called When everything you know is wrong talking about finalizer myths, I suggest you take a look.
Edit:
Funny, Erics second post (posted today) in the series answers this question:
Myth: Finalizers run in a predictable order
Suppose we have a tree of objects, all finalizable, and all on the finalizer queue. There is no requirement whatsoever that the tree be finalized from the root to the leaves, from the leaves to the root, or any other order.
As screamed many times earlier, finalizers don't guarantee any order. You can't make any assumptions. You should assume the worst (i.e) it can be executed in any order.
As there clearly is a "hidden" order for each class, can I trust it?
Yes and no.
For normal objects order of execution of finalizers is unpredictable. So no. You can't rely anything in it.
For objects which inherits from SafeHandle
, yes there is some ordering. For example: If you get two objects ready for finalization, one is derived from SafeHandle
and other is not, then it is guaranteed that the finalizer of object which doesn't inherit from SafeHandle
will be executed before the SafeHandle's finalizer is executed.
This ordering exist for a reason which is described in this blog post. This isn't documented but blogged by BCL team. It is unlikely to be changed in future. But...
To prove it, the following program will always finalize Destructor
class first then MyClass
. Because you know MyClass
inherits from SafeHandle
.
public class MyClass : SafeHandle
{
private static readonly Destructor DestructorObject = new Destructor();
~MyClass()
{
Console.WriteLine("Destructor Called");
}
protected override bool ReleaseHandle()
{
return true;
}
public override bool IsInvalid
{
get { return false; }
}
static void Main(string[] args)
{
var myClass = new MyClass(IntPtr.Zero, true);
}
private sealed class Destructor
{
~Destructor()
{
Console.WriteLine("Static Destructor Called");
}
}
public MyClass(IntPtr invalidHandleValue, bool ownsHandle)
: base(invalidHandleValue, ownsHandle)
{
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With