我的应用程序中的库需要全局使用非托管资源。
为方便起见,该库具有以下内容:
IDisposable
的单例类。
Instance()
方法中。
MySingleton
对象访问资源,因此这似乎是确保非托管资源在需要时可用的合理方式。
public class MySingleton : IDisposable
{
private static MySingleton instance;
public static MySingleton Instance
{
get
{
if (instance == null)
{
lock (typeof(MySingleton))
{
if (instance == null)
{
instance = new MySingleton();
// Acquire unmanaged resource here
}
}
}
return instance;
}
}
public void Dispose()
{
// Release unmanaged resource here
}
}
MySingleton.Instance.Dispose()
(通常在finally
块中,以确保即使在exception
情况下也会发生这种情况Dispose
方法,则可能导致未正确清理非托管资源。我尝试在MySingleton
类中添加了一个析构函数来执行此操作,但在应用程序退出时似乎没有出现断点。我猜这是因为GC是非确定性的,也许应用程序在静态对象的析构函数被销毁之前结束,但我不确定。
是否有一种优雅的方法可以确保始终清理此资源,而无需依赖显式调用Dispose
的客户端应用程序来确保这种情况发生?
答案 0 :(得分:2)
对单例的静态引用将使其保持活动状态,无论其他人是否实际使用它。如果您希望检测到您的单身人士的所有外部引用何时消失而不让自己保持活着,则必须执行以下某项操作:
如果您的资源是在旧实例存在时无法重新创建的资源,那么我的建议通常是方法#2。方法#1的问题在于,如果有多个可终结对象与资源相关联,则可能存在大量间隔,在此期间资源被部分清理,因此代码可能别无选择,只能等待其他对象'终结者完成。当使用方法#2时,如果在终结器处于挂起状态时请求单例,则请求将很快到来以防止终结器执行清理(在这种情况下,它不需要等待终结器运行,因为终结器赢了'实际上做了什么),它将在终结器运行之后(在这种情况下可以立即创建新实例),或者在终结器执行清理时(这是最坏的情况 - 代码必须等待)对象自己的清理要完成,但不必等待其他人的最终确定。)
答案 1 :(得分:1)
单独使用IDisposable听起来有误。谁负责处理该物体?
当两个线程或两个进程尝试访问资源时应该发生什么?失败者应该阻止或抛出异常吗?
我认为你最好采用RAII方法,你有一个实现IDisposable的类,并且只能在资源正在使用的时候生存:
class MyResource : IDisposable {
public MyResource() {
// Acquire resource here
}
public void Dispose() {
// Free resource here, along with extra stuff to attempt
// to catch situations where its not disposed
}
}
然后:
using( var r = new MyResource() ) {
// Do work here.
}
你不能保证使用你的库的每个其他开发人员都会记得正确地处理这个类,但是任何未能在using语句中使用该类的人都可以用一个大棒的方法进行教育。
答案 2 :(得分:0)
关于你的析构函数没有被击中,请看这里: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx 析构函数被调用,但我不认为你可以在调试时看到它。 至于你的单身人士,显然在程序退出之前不会被调用,因为它是静态的。
关于确保调用Dispose,我认为你能做的最好就是继承IDisposable并记录需要处理。如果有办法自动处理事物,你不觉得MS会对SqlConnection或任何其他一次性类做过吗?顺便说一句,我认为确定何时将一个实例放置在类本身中是不好的做法。这样就限制了你的类的使用,你无法知道将使用你的类的其他组件想要做什么。