kateroh
kateroh

Reputation: 4416

Disposing a singleton instance (C#)

If a singleton implements IDisposable, what is the right way of disposing and re-creating an instance? One way would be to keep _disposed flag and check for it in the Instance property, but I'm not sure it is the right way to do this. A simple example:


public sealed class Singleton: IDisposable
{
   private static Singleton _instance;
   private object _lock;
   private UnmanagedResource _unmanaged;
   private bool _disposed;

   private Singleton()
   {
      _unmanaged = new UnmanagedResource();
      _disposed  = false;
      _lock      = new object();
   }

   public UnmanagedResource Unmanaged { get { return _unmanaged; } }

   public static Singleton Instance
   {
      get
      {
         if (_instance == null || _disposed)
         {
            lock (_lock)
            {
               if (_instance == null || _disposed)
               {
                  _instance = new Singleton();
               }
            }
         }
         return _instance;
      }
   }

   public void Dispose()
   {
      _disposed = true;
      try
      {
         _unmanaged.Dispose();
      }
      finally
      {
         GC.SuppressFinalize(this);
      }
   }
}

So that code likes this is possible (though, yes I agree, it kind of defeats the purpose of having a Singleton):


Singleton.Instance.Dispose();
Singleton.Instance.Unmanaged.UseResource();   // Unmanaged shouldn't be null.

NOTE: There is no need to overemphasize incompatibility between Singleton and IDisposable, I understand it. I need Dispose method to free unmanaged resources when ApppDomain unloads. If you have a problem with this class being called Singleton, I can rename it LoadBalancer instead. The question will still remain the same. This LoadBalancer needs to be disposable, because it's instance does not belong to anyone, but should be properly disposed.

Upvotes: 3

Views: 14674

Answers (4)

Brian Gideon
Brian Gideon

Reputation: 48959

I am not seeing how this is going to work. Consider this hypothetical use case:

using (Singleton instance = Singleton.Instance)
{
  // Do stuff with the instance.
}

How are you going to guard against multiple threads executing this code simultaneously? One thread could call Dispose while another is still trying to use the same instance. Trying a force an API with recycling semantics into the singleton concept is like trying to fit a square peg in a round hold.

By the way, there is tangential problems worth mentioning. The Instance property is not thread-safe. At the very least you will have to mark _instance as volatile. And that is only if you were using the canonical implementation of the pattern. You will never be able to make the pattern safe since you also use the _disposed flag as extra criteria in the check. Personally, I would just scrap the double-checked locking pattern altogether.

Upvotes: 2

JaredPar
JaredPar

Reputation: 755457

Singleton and Disposable objects are largely incompatible concepts

  • Singletons are a single instance of a type which is available for the life time of the application
  • Disposable objects are those which need dispose of resources in a timely manner after they're no longer used.

Singletons are generally speaking alive for the lifetime of a process / AppDomain. If you find yourself wanting to Dispose them then you probably need to refactor your solution a bit.

If the problem is around the freeing of resources during an AppDomain unload then put the responsibility of freeing the resource with the same object responsible for managing the life time of the AppDomain. Then embed this resource in the Singleton without implementing IDisposable. This will properly separate out the concerns of the scenario.

Upvotes: 6

DarkSquirrel42
DarkSquirrel42

Reputation: 10287

if you need to replace the instance of a singleton, you should think about your design.

if you REALLY think you should do this, i'd suggest to use 2 objects ...

one singleton object that acts as a proxy, and is a real singleton (end of lifetime == end of process)

this object needs public members for everything your singleton is capable of, and one private member holding the real implementing object. all other members redirect to members of that implementation.

the second object is the disposable object that can be replaced. make sure that only your singleton object will ever hold a reference on that... this way it doesn't matter if any consumer object holds a reference on the singleton that would prevent you from replacing the object ... that ref will only point to a proxy

Upvotes: 6

ist_lion
ist_lion

Reputation: 3209

Maybe I'm asking a dumb question but why would you want to dispose a Singleton only to create a new one? Isn't the purpose to have a single instance....

This could be a design issue I'm not aware of. Maybe the "right way" in this case is to re-evaluate what you need your code to do and what pattern gets you there.

Upvotes: 0

Related Questions