我应该在单例上实现IDisposable吗?

6

我有一个Windows服务,其中包含一个单例,该单例又使用一些记录器、消息队列监听器等。这些类实现了IDisposable。我应该在单例本身中实现IDisposable,还是需要进行其他操作以确保在服务停止/崩溃后,所有本地资源都不会出现问题?

该单例的实现如下:

public class Temp
{
   private static readonly Lazy<Temp> instance = new Lazy<Temp>(() => new Temp());

   private Temp()
   {
      // create IDisposable objects which use native resources
   }

   public static Temp Instance
   {
      get
      {
         return instance.Value;
      }
   }
} 

在这里使用Lazy是完全没有意义的。 - weston
@weston http://csharpindepth.com/articles/general/singleton.aspx - Qué Padre
很有可能,在Windows服务中根本不需要实现单例模式。为什么你需要它呢? - nvoigt
3个回答

5

我宁愿不在单例上实现IDisposable接口:IDisposable会促使开发人员对(单个)实例进行Dispose操作。

  using(var temp = Temp.Instance) {
    ...
  }

这可能导致应用程序的其他部分发生崩溃(因为单个Temp实例已被处理)。
  Temp.Instance.SomeFucntion(); // <- possible fail, since Temp.Instanceis disposed

在一些罕见的情况下,如果您必须释放一些已获取的资源,我建议使用ProcessExit事件。

public class Temp {
   private static readonly Lazy<Temp> instance = new Lazy<Temp>(() => new Temp());

   private void OnProcessExit(Object sender, EventArgs e) {
     // Release native resource if required:
     // some resources e.g. files will be closed automatically,
     // but some e.g. transactions should be closed (commit/rollback) manually
     try {  
       ...
     }
     finally { 
       AppDomain.CurrentDomain.ProcessExit -= OnProcessExit;
     }   
   }

   private Temp() {
     // create IDisposable objects which use native resources

     // If you have to release some resouces on exit
     AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
   }

   public static Temp Instance {
     get {
       return instance.Value;
     }
   }
} 

我认为应该在 finally 语句块中使用 AppDomain.CurrentDomain.ProcessExit -= OnProcessExit;。 - Qué Padre
@Qué Padre:谢谢!你说得很对:应该是AppDomain.CurrentDomain.ProcessExit -= OnProcessExit。 - Dmitry Bychenko
我尝试使用Ctrl+C退出控制台应用程序,但看起来在这种情况下事件也没有被触发。以下是原文链接:http://blogs.msdn.com/b/jmstall/archive/2006/11/26/process-exit-event.aspx。 - Qué Padre
是的,当您异常退出应用程序(显式进程终止、在控制台应用程序上按Ctrl+C等)时,既不会触发ProcessExit,也不会执行finally - 如果您想要终止应用程序而不需要任何其他操作(比如应用程序挂起在ProcessExit上),则应该直接终止应用程序。 - Dmitry Bychenko

2

不应该在单例模式中实现IDisposable接口。如果有人在其他人需要它时过早地释放了实例,会怎么样?

同时,请注意,当您的服务崩溃/停止时,实现IDisposable也无法帮助您。你必须手动处理!但是你找不到合适的时间去做。


那么,在这里我能做什么? - Qué Padre

1
如果工厂返回的类型在调用者完成后有时需要清理,则该类型应实现IDisposable。如果特定的工厂返回一个不需要任何资源的共享单例对象,则工厂返回的对象应具有一个Dispose方法,该方法会默默地什么也不做。如果工厂需要提供对共享单例资源的访问(例如存储在GDI对象中的不可变位图),则它应返回一个包装器,该包装器将在其Dispose方法被调用时通知工厂;然后,工厂可以维护包装器对象的引用计数,并在知道不会创建更多包装器并且所有现有包装器都已被处理后清理资源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接