After last week's Java finalization bashing,
it turns out that C# is even more broken.
A C# Destructor Cannot Be Sealed
This is really bad! If you recall my example of a proper class that uses finalization
correctly, you might remember that the class was final. I still highly recommend
this, but in some scenarios it might be preferable to allow others to extend your
class. In such cases it is highly recommended that you make your
finalize method final. Otherwise the subclasser might override finalize and forget
to call your finalize method.
If you wrap an unmanaged resource and your class is non-final and it is exposed to
untrusted code, you must make your finalize method final.
If you don't, the untrusted code can (intentionally or not) create a subclass of your
class, override finalize (not call super.finalize()) and start leaking unmanaged resources
that will never be cleaned up as long as the JVM is running.
Back To C#
To see why the C# design is a problem, we only need to look at System.WeakReference.
It is a public non-sealed class that wraps an unmanaged resource (a GCHandle),
the destructor is obviously not sealed and it does not require any privileges to use,
this equals a recipe for disaster. Untrusted code can leak GCHandles that will never
be reclaimed as long as the CLR is running [1]. Not even when the AppDomain is unloaded!
IMO, the destructor syntax should be deprecated and Finalize should be treated like
any other method. This current design is hardly a pit
of success.
[1] While the C# destructor is nice enough to always call the base class Finalize
method, other languages (e.g. ILASM or VB.NET) don't require this.