views:

861

answers:

5

This is what I understand about IDisposable and finalizers from "CLR via C#", "Effective C#" and other resources:

  • IDisposable is for cleaning up managed and unmanaged resources deterministically.
  • Classes that are responsible for unmanaged resources (e.g. file handles) should implement IDisposable and provide a finalizer to guarantee that they are cleaned up even if the client code does not call Dispose() on the instance.
  • Classes that are responsible for managed resources only should never implement a finalizer.
  • If you have a finalizer then you must implement IDisposable (this allows client code to do the right thing and call Dispose(), while the finalizer prevents leaking resources if they forget).

While I understand the reasoning for and agree with all of the above, there is one scenario where I think it makes sense to break these rules: a singleton class that is responsible for unmanaged resources (such as providing a single point of access to particular files).

I believe it is always wrong to have a Dispose() method on a singleton because the singleton instance should live for the life of the application and if any client code calls Dispose() then you are stuffed. However, you want a finalizer so that when the application is unloaded the finalizer can clean up the unmanaged resources.

So having a singleton class with a finalizer that does not implement IDisposable seems to me to be a reasonable thing to do, yet this type of design is counter to what I understand are best practices.

Is this a reasonable approach? If not, why not and what are the superior alternatives?

+2  A: 

I'd first mention that Object Oriented design patterns and their consequences do not always influence every language decision, even in Object Oriented languages. You can certainly find classic design patterns that are easier to implement in one language (Smalltalk) as opposed to another (C++).

That being said, I'm not sure I agree with the premise that a singleton instance should only be disposed at the end of an application. Nothing in the design pattern descriptions that I've read for Singleton (or Design Patterns: Elements of reusable Object-Oriented Software) mention this as a property of this pattern. A singleton should ensure that only one instance of the class exists at any one moment in time; that does not imply that it must exist for as long as the application exists.

I have a feeling that in practice, many singletons do exist for most of the life of an application. However, consider an application that uses a TCP connection to communicate with a server, but can also exist in a disconnected mode. When connected, you would want a singleton to maintain the connection information and state of the connection. Once disconnected, you may want to keep that same singleton - or you may dispose of the singleton. While some may argue that it makes more sense to keep the singleton (and I may even be among them), there is nothing in the design pattern itself that precludes you from disposing of it - if a connection is remade, the singleton can be instantiated again, as no instance of it exists at that moment in time.

In other words, you can create scenarios where it is logical for singletons to have IDisposable.

Matt Jordan
+1  A: 

As long as your finalizer doesn't call methods (such as Dispose) on any other managed objects, you should be fine. Just remember that finalization order is not deterministic. That is, if your singleton object Foo holds a reference to object Bar that requires disposal, you cannot reliably write:

~Foo()
{
    Bar.Dispose();
}

The garbage collector might have collected Bar already.

At the risk of stepping into a pile of OO goo (i.e. starting a war), one alternative to using a singleton is to use a static class.

Jim Mischel
+1 for static class - singletons are not as necessary as their ubiquity would suggest.
Andrew Hare
Conceptually the only difference between a singleton and a static class is that a singleton is one static field that points at many instance fields, where a static class is a bunch of static fields.When it comes to resource management, the differences between the 2 are negligible.
Scott Wisniewski
what scott said - disposable singletons are just a fundamental problem
annakata
Can the GC really have collected Bar? From what I've read elsewhere, while Bar may have been finalized, objects which are referenced by one that's awaiting finalization Foo are eligible for finalization but not garbage-collection; I am seeking some clarification on that point, though. Of course, calling Bar.Dispose will be unsafe unless one knows that it will not acquire any locks, create any new objects, or throw any exceptions (I think even a caught exception may be dangerous due to the creation of the Exception object), but other actions might be safe.
supercat
+1  A: 

While it may get you code review gripes and FxCop warnings, there's nothing intrinsically wrong with implementing a finalizer without IDisposable. However, doing so on a singleton is not a reliable way to capture process or AppDomain tear-down.

At the risk of offering subjective design advice: If the object is truly stateless, make it a static class. If it is stateful, question why it is a Singleton: you're creating a mutable global variable. If you're trying to capture application close, deal with it when your main loop exits.

Jeffrey Hantin
"If the object is truly stateless, make it a static class. If it is stateful, question why it is a Singleton" I completely agree, but I like the snappiness of the quoted. Got a reference for that?
annakata
I made that one up on the fly. I've been railing against most uses of Singletons for some time now on the Portland Pattern Repository due to their effect on causality in the code.
Jeffrey Hantin
+2  A: 

If the unmanaged resource is released only on application exit you don't even need to worry with a finalizer since the process unload should deal with this for you anyway.

If you have multiple app domains and you want to deal with an app domain unload that's one possible issue but possibly one you don't need to care about.

I second those saying that this design is possibly not the right thing to do (and will make it harder to fix is subsequently you find that you do actually need two instances) Create the object (or a lazy loading wrapper object) in your entry point and pass it through the code to where it is needed making it clear who is responsible for providing it to whom, then you are free to change the decision to use only one with little effect to the rest of the code (which uses what it gets given)

ShuggyCoUk
A: 

Applicability of Singleton to any particular situation aside,

I think there is nothing wrong with Disposing of Singleton. In combination with lazy instantiation it just means that you release resource if you do not need it temporarily, and then re-acquire it as needed.

Alexander Abramov
That one piece of code might acquire and "Dispose" a singleton says nothing about whether anyone else might still be using it. If the finalizer gets called, nobody's using it; note that the only way that would likely happen would be if the static/global reference to the singleton were a WeakReference. Otherwise that reference would itself protect the singleton from finalization.
supercat