处理单例实例(C#)

kat*_*roh 2 c# singleton .net-3.5

如果单例实现了IDisposable,那么处理和重新创建实例的正确方法是什么?一种方法是保持_disposed标志并在Instance属性中检查它,但我不确定这是否是正确的方法.一个简单的例子:


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);
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

所以代码喜欢这个是可能的(但是,我同意,它有点击败了拥有Singleton的目的):


Singleton.Instance.Dispose();
Singleton.Instance.Unmanaged.UseResource();   // Unmanaged shouldn't be null.
Run Code Online (Sandbox Code Playgroud)

注意:没有必要过分强调Singleton和IDisposable之间的不兼容性,我理解.当ApppDomain卸载时,我需要Dispose方法来释放非托管资源.如果您将此类称为Singleton有问题,我可以将其重命名为LoadBalancer.问题仍将保持不变.这个LoadBalancer需要是一次性的,因为它的实例不属于任何人,但应妥善处置.

Jar*_*Par 6

Singleton和Disposable对象在很大程度上是不兼容的概念

  • 单身人士是一种类型的单一实例,可在申请的整个生命周期内使用
  • 一次性物品是指在不再使用后需要及时处理资源的物品.

单身人士通常在一个过程的生命周期中说活着AppDomain.如果你发现自己想要Dispose它们,那么你可能需要稍微重构一下你的解决方案.

如果问题是在AppDomain卸载期间释放资源,则将负责释放资源的责任与负责管理生命周期的相同对象放在一起AppDomain.然后在Singleton没有实现的情况下将此资源嵌入IDisposable.这将正确地分离出场景的顾虑.

  • @kateroh:为什么不实现清理那些非托管资源的终结器?在大多数情况下,终结器会在AppDomain终止时被调用.在罕见的强制中止中,您仍然可以通过"CriticalFinalizerObject"依赖关键终结器. (3认同)

Dar*_*l42 6

如果你需要替换单例的实例,你应该考虑你的设计.

如果你真的认为你应该这样做,我建议使用2个对象......

一个单独的对象充当代理,并且是一个真正的单例(生命周期结束==进程结束)

这个对象需要公共成员来处理你的单身人士所能拥有的一切,以及一个拥有真正实现对象的私有成员.所有其他成员重定向到该实现的成员.

第二个对象是可以更换的一次性物体.确保只有你的单例对象才会持有对它的引用...这样,如果任何一个消费者对象在单例上保存一个阻止你替换对象的引用并不重要......那个引用只会指向代理人