在Singleton上使用Dispose来清理资源

我的问题可能更多地与语义有关,而不是与IDisposable的实际使用有关。 我正在实现一个单例类,负责管理在执行应用程序期间创建的数据库实例。 应用程序关闭时,应删除此数据库。

现在我将删除操作由应用程序在关闭时调用的单例的Cleanup()方法处理。 当我编写Cleanup()的文档时,让我感到震惊的是我正在描述应该使用Dispose()方法来清理资源。 我原本没有实现IDisposable因为它在我的单身中看起来不合适,因为我不想要任何东西来处理单身本身。 目前还没有,但将来可能会出现这样一个原因:可能会调用此Cleanup()但单例仍然需要存在。 我想我可以包含GC.SuppressFinalize(this); 在Dispose方法中使这个可行。

因此,我的问题是多方面的:

1)在单例上实现IDisposable从根本上说是一个坏主意吗?

2)我只是通过使用Cleanup()而不是Dispose()来混合语义,因为我正在处理资源我真的应该使用dispose吗?

3)用GC.SuppressFinalize(this);实现’Dispose()’ GC.SuppressFinalize(this); 这样我的单身实际上并没有被破坏,因为我希望它在调用清理数据库后生存。

简而言之,如果你有一个单身人士并且你打电话处理。 任何对象在此之后尝试使用它时,将使用处于已处置状态的对象。

现在将它放入,并在应用程序完成后处理对象,并不一定是坏事。 当你打电话时,你必须要小心。 如果您真的关心清理并且只有一个引用它,那么您可以将清理代码放在对象终结器~YourClass ,只会通过.Net调用它确定不再需要它(当时应用程序关闭,如果它是一个真正的单身人士)。

我只是通过使用Cleanup()而不是Dispose()来混合语义,因为我正在处理资源我真的应该使用一个dispose吗?

是的,这只是语义。 Dispose是显示在程序完成对象后需要清除的东西的标准。

将使用GC.SuppressFinalize(this)实现’Dispose()’; 这样我的单身实际上并没有被破坏,因为我希望它在调用清理数据库后生存。

不,这意味着当你调用dispose方法时,垃圾收集器不会调用对象的自定义终结器。

  1. 如果使用CAS技术而不是锁来创建单例,那么为单例实现IDisposable 可能是个好主意。 像这样的东西。

     if (instance == null) { var temp = new Singleton(); if (Interlocked.CompareExchange(ref instance, temp, null) != null) && temp is IDisposable) { ((IDisposable)temp).Dispose(); } } return instance 

    我们创建了一个临时对象并尝试了primefacesCompare-and-Swap,因此如果它实现了IDisposable并且没有写入实例的位置,我们需要处理这个临时对象。

    如果使用一些重逻辑在其构造函数中创建单例的实例,那么避免锁可能是好的,但也有点开销。

  2. 如果您不希望其他代码清理或处置您的对象,请不要为此提供任何机会。 但是,提供某种reset()方法以允许单例重新创建自身(如果使用惰性init) 可能是个好主意。 像这样的东西:

     public static Singletong GetInstance() { if (instance == null) { instance = new Singleton(); //here we re-evalute cache for example } return instance } public static void Reset() { instance = null; } 

我同意凯文的答案,但是想补充一点。 我对你的陈述有点困惑:

应用程序关闭时,应删除此数据库。

你的意思是删除吗? 在毁灭? 你在谈论真正的(SQL)数据库吗?

您必须明白,即使您将清理代码放在终结器中,或者在Application_End事件(ASP.NET)中,也无法保证调用这些代码。 该过程可以终止,或者计算机断电。 在应用程序启动时删除数据库似乎更合理,或者至少在启动时通过一些清理具有回退机制。

虽然终结器在处理资源时是一个放置清理的好地方,但在你的情况下我们讨论的是应用程序资源 。 我的意思是,资源可能不是绑定到单个对象(您的单例),而是整个应用程序的一部分。 这可以得到一些抽象的讨论,这可能更多的是一个观点问题。

我想说的是,当您将该数据库视为应用程序资源时,您必须将初始化和清理不必绑定到对象,而是绑定到应用程序。 在ASP.NET应用程序中,这将是Application_Start和Application_End(global.asax)。 在Windows窗体应用程序中,这将是Program.Main。

但是,当使用这些机制而不是终结器时,您无法确定清理代码是否会执行。