Introduction
I was reviewing some Delphi code and, while doing so, I noticed an old "friend" of mine: the initialization
and finalization
sections of units. Not all units bear them, but they represent the first and last blocks of code to be executed for that unit. And this can be verified if you debug an application step by step: all initialization sections are executed before any other line on the main procedure is executed.
Just as I watched those lines of code, I started to wonder: I can replace an initialization
with some static
constructor, with the advantage that it'll only execute if I need that class. But how about the finalization
section?
Instance Destructors
For those used to C#, a destructor can be declared in two ways:
class MyClass {
~MyClass() {
}
protected override void Finalize() {
try {
} finally {
base.Finalize();
}
}
}
In the end, either way will translate into the same IL, but you cannot have both on the same class. I'm not very familiar with VB.NET, but only one version exists here:
Class MyClass
Overrides Protected Sub Finalize()
End Sub
End Class
This will have the same effect as the C# codes and, in both languages, enables you to finish open (or forgotten open) connections, record logs of an object's destruction and so forth. But what do you do when you want some behavior when an application is being terminated?
Static Constructors
There is no straight way to provide the same for the entire class. But as I gave thought to the matter, I came up with the smallest possible code to achieve it. This approach goes through a static
constructor. Why? Because it is granted to be executed only once (if it's not, I believe it's a bug) the first time a class is referenced, no matter for which purpose. This is also an excellent point to create singletons for the same reason (isn't that what we want with a singleton?).
At this point, if you're very familiar with the singleton pattern, you might already have a fair idea of how to create the static destructor.
If you didn't guess, here is the answer: since a singleton is an instance of an object and instances can bear Finalize
methods, all we have to do is to instantiate a singleton class (perhaps private
) which will do the job we want. That class is instantiated in the static
constructor. Take a look:
class MyClass {
private static readonly StaticDestructor sd = new StaticDestructor();
private class StaticDestructor {
~StaticDestructor() {
}
}
}
There is no need to be manipulating such an object. For as long as the reference exists, the object will not be disposed by the CG (so I expect; it's meant to be this way). When the application terminates, any objects pending finalization will be disposed naturally, thus allowing our pseudo static
destructor to be called.
Although, it's important to notice that, just as static
constructors, static
destructors are meant to deal with static
elements. Despite the fact that the StaticDestructor
class has an instance, it doesn't belong to any particular instance of MyClass
.
Unloading Order
As spotted out by carlopagliei, this approach does not consider the fact that, in Delphi, finalization
sections are executed in reverse order of initialization
sections. But how could this be done in an object oriented way?
Not with our previous approach, for sure. The need to recall the order in which classes have been "initialized", if you need to reverse its actions in a precise order, renders it useless. The only managed way to do this is to register every finalization
section we need to be called. This will demand an auxiliary class and the use of some reflection.
public sealed class CodeManager {
private static List<MethodInfo> actions = new List<MethodInfo>();
private static CodeManager singleton = new CodeManager();
private static List<Type> types = new List<Type>();
private CodeManager() { }
~CodeManager() {
foreach(MethodInfo mi in actions)
mi.Invoke(null, null);
}
public static void Register(Type type) {
if(types.Contains(type)) return;
types.Add(type);
MethodInfo mi = type.GetMethod("Initialization", BindingFlags.Static |
BindingFlags.Public | BindingFlags.NonPublic, null, Types.EmptyType, null);
if(mi != null) mi.Invoke(null, null);
mi = type.GetMethod("Finalization", BindingFlags.Static |
BindingFlags.Public | BindingFlags.NonPublic, null, Types.EmptyType, null);
if(mi != null) actions.Insert(0, mi);
}
}
This class is a little bit more complex, but analyzing its code, you will notice it'll demand you to register a class so it can be finalized, but this behavior is not needed for initializations. It's best if you perform initializations inside the static
constructor, to ensure its code won't be executed twice.
You will need one or two methods declared static
and have no return value or extra arguments to be called. Declaring them as public
is optional, but if you obfuscate the assembly, you may lose their reference by name. They should be declared as follows:
public static void Initialization() { ... }
public static void Finalization() { ... }
However, there is a flaw in this approach as well, as the initialization
methods are exposed and become prone to a second call. The same is valid for the finalization
section. It's important to remember that code inside these methods are meant to be executed only once during the application's lifetime. So, using the static
constructor whenever possible can be considered a good practice.
Points of Interest
I have actually found no need for a static
destructor myself, but you can use it virtually anywhere. Some possible uses might be:
- Centralized logging: you could dispose of the log service appropriately
- Special object control: some instances should be coordinated during disposal
- Global connection with a server: all data comes through a single coordinated connection (this can be done with a simple singleton and it's own destructor, but you're the developer)
Some optimization tools might understand that there is no use for the object in the first approach or its class and simply remove them from IL. There are only two ways to contour this: not to optimize, or to inject some code into the destructor which is used (even vaguely) by the main
class. This method could be a simple sum of two numbers or some encryption routine, but it's important not to be empty. If it's referenced in two or more methods in the main
class, the better. For the second approach, declaring the methods private
or internal
may cause removal of their name, disabling reflection.
Also, I haven't tried to access instance members inside the static
destructor in the first approach, but I believe it's not possible once the inner class instance is held static
. Surely you can access the static
destructor class from instances, that's the reason why I mark the static
field read-only.