Disposing a singleton instance (C#)

感情迁移 提交于 2019-12-10 10:43:18

问题


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.


回答1:


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




回答2:


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.




回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/6229079/disposing-a-singleton-instance-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!