The question I have might be more to do with semantics than with the actual use of IDisposable
. I am working on implementing a singleton class that is in charge of managing a database instance that is created during the execution of the application. When the application closes this database should be deleted.
Right now I have this delete being handled by a Cleanup()
method of the singleton that the application calls when it is closing. As I was writing the documentation for Cleanup()
it struck me that I was describing what a Dispose()
method should be used for i.e. cleaning up resources. I had originally not implemented IDisposable
because it seemed out of place in my singleton, because I didn't want anything to dispose the singleton itself. There isn't currently, but in the future might be a reason that this Cleanup()
might be called but the singleton should will need to still exist. I think I can include GC.SuppressFinalize(this);
in the Dispose method to make this feasible.
My question therefore is multi-parted:
1) Is implementing IDisposable
on a singleton fundamentally a bad idea?
2) Am I just mixing semantics here by having a Cleanup()
instead of a Dispose()
and since I'm disposing resources I really should use a dispose?
3) Will implementing 'Dispose()' with GC.SuppressFinalize(this);
make it so my singleton is not actually destroyed in the case I want it to live after a call to clean-up the database.
Implementing IDisposable for singleton might be good idea if you use a CAS techinque instead of locks to create a singleton. Something like this.
if (instance == null) {
var temp = new Singleton();
if (Interlocked.CompareExchange(ref instance, temp, null) != null) &&
temp is IDisposable) {
((IDisposable)temp).Dispose();
}
}
return instance
We created a temporary object and tried atomic Compare-and-Swap so we need to dispose this temporary object if it impletents IDisposable and it wasn't written to instance's location.
It might be good to avoid locks but also it's a bit overhead if some heavy logic is used to create a singleton's instance in its constructor.
If you don't want other code to cleanup or dispose your object just don't provide any opportunity for this. However, it might be good idea to provide some kind of reset() method to allow singleton to recreate itself if, let say, you use a lazy init. Something like this:
public static Singletong GetInstance() {
if (instance == null) {
instance = new Singleton(); //here we re-evalute cache for example
}
return instance
}
public static void Reset() {
instance = null;
}
In short, if you have a singleton and you call dispose. Any time that any object tries to use it after that, will be using an object in a disposed state.
Now putting it in, and disposing of the object after the application is done with it, isn't necessarily bad. You do have to be careful though when you call it. If you are really concerned with the cleanup and you have only one reference to it, you can put the clean up code in the objects finalizer ~YourClass
that way it will only be called with .Net is sure it is no longer needed (when the application closes, if it is a true singleton).
Am I just mixing semantics here by having a Cleanup() instead of a Dispose() and since I'm disposing resources I really should use a dispose?
Yes, this is just semantics. Dispose is the standard for showing there are things that need to be cleared up after the program is done with the object.
Will implementing 'Dispose()' with GC.SuppressFinalize(this); make it so my singleton is not actually destroyed in the case I want it to live after a call to clean-up the database.
No what this means is that when you call the dispose method, the Garbage Collector won't call the object's custom finalizer.
I agree with Kevin's answer, but like to add something to this. I'm a bit confused about your statement:
When the application closes this database should be deleted.
Do you really mean deleted? As in destroyed? Are you talking about a real (SQL) database?
You must understand that even if you put your clean up code in a finalizer, or in the Application_End event (ASP.NET) there is no way you can guarantee these are called. The process can be terminated, or the computer loses power. It seems more reasonable to delete the database on application startup, or at least have a fallback mechanism at startup with some cleanup.
While the finalizer would be a good place to put cleanup when dealing with resources, in your case we're talking about an application resource. What I mean by this is that the resource isn't perhaps bound to a single object (your singleton) but is part of the whole application. This can get a bit an abstract discussion, and it's perhaps more a matter of view.
What I'm trying to say it that when you see that database as a application resource, you will have to have your initialization and cleanup not bound to an object, but to the application. In an ASP.NET application this would be Application_Start and Application_End (global.asax). In an Windows Forms application, this would be Program.Main.
Still, when using these mechanisms over finalizers, you have no certainty that your clean up code will execute.
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