我的问题可能更多地与语义有关,而不是与IDisposable
的实际使用有关。我正在开发一个单例类,负责管理在执行应用程序期间创建的数据库实例。应用程序关闭时,应删除此数据库。
现在我将此删除操作由应用程序在关闭时调用的单例的Cleanup()
方法处理。当我写Cleanup()
的文档时,我感到震惊的是我正在描述应该使用Dispose()
方法来清理资源。我原本没有实现IDisposable
,因为它在我的单身中似乎不合适,因为我不想要任何东西来处理单身人士本身。目前还没有,但将来可能是这个Cleanup()
可能被调用的原因,但单身人员应该仍然存在。我想我可以在Dispose方法中包含GC.SuppressFinalize(this);
以使其可行。
因此,我的问题是多方面的:
1)对单身人员实施IDisposable
从根本上说是一个坏主意吗?
2)我只是通过使用Cleanup()
而不是Dispose()
来混合语义,因为我正在处理资源我真的应该使用处理吗?
3)使用GC.SuppressFinalize(this);
实现'Dispose()'会使我的单例实际上没有被破坏,因为我希望它在调用清理数据库后生存。
答案 0 :(得分:8)
简而言之,如果你有一个单身人士并且你打电话处理。任何对象在此之后尝试使用它时,都将使用处于已处置状态的对象。
现在将它放入,并在应用程序完成后处理对象,并不一定是坏事。当你打电话时,你必须要小心。如果您真的关心清理并且只有一个引用它,那么您可以将清理代码放在对象终结器~YourClass
中,这样只会调用它.Net确定不再需要它(当应用程序关闭时,如果它是一个真正的单例)。
我只是在这里混合语义 有一个清理()而不是一个 Dispose()因为我正在处理 资源我真的应该用 处置?
是的,这只是语义。 Dispose是显示在程序完成对象后需要清除的东西的标准。
将实现'Dispose()' GC.SuppressFinalize(本);这样做 我的单身实际上并没有被摧毁 在这种情况下,我希望它生活在一个 打电话来清理数据库。
否则这意味着当您调用dispose方法时,垃圾收集器将不会调用该对象的自定义终结器。
答案 1 :(得分:7)
如果使用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
我们创建了一个临时对象并尝试了原子Compare-and-Swap,因此如果它实现了IDisposable并且没有写入实例的位置,我们需要处理这个临时对象。
如果使用一些重逻辑在其构造函数中创建单例的实例,那么避免锁可能会很好,但也有点开销。
如果您不希望其他代码清理或处置您的对象,请不要为此提供任何机会。但是,可能可能提供某种reset()方法以允许单例重新创建自己,如果你使用lazy 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;
}
答案 2 :(得分:1)
我同意Kevin的回答,但是想在此添加一些东西。我对你的陈述感到有点困惑:
当应用程序关闭此时 数据库应该被删除。
你的意思是删除吗?如在被毁?你在谈论真正的(SQL)数据库吗?
您必须明白,即使您将清理代码放在终结器中,或者在Application_End事件(ASP.NET)中,也无法保证调用这些代码。该过程可以终止,或者计算机断电。在应用程序启动时删除数据库似乎更合理,或者至少在启动时使用回退机制进行一些清理。
虽然终结器在处理资源时是一个放置清理的好地方,但在你的情况下我们讨论的是应用程序资源。我的意思是资源可能不是绑定到单个对象(您的单例),而是整个应用程序的一部分。这可以得到一些抽象的讨论,这或许更像是一个观点问题。
我想说的是,当您将该数据库视为应用程序资源时,您必须将初始化和清理不必绑定到对象,而是绑定到应用程序。在ASP.NET应用程序中,这将是Application_Start和Application_End(global.asax)。在Windows窗体应用程序中,这将是Program.Main。
但是,当使用这些机制而不是终结器时,您无法确定清理代码是否会执行。