Dav*_*ave 8 c# dispose idisposable
我有一些关于C#中的Dispose模式的基本问题.
在下面的代码片段中,您似乎是实现dispose模式的标准方法,您会注意到如果disposing为false,则不会处理托管资源.他们如何/何时处理?GC是否会出现并在以后处理托管资源?但如果是这样的话,GG.SuppressFinalize(this)调用会做什么?有人能给我一个处理托管资源的例子吗?想到了解开事件的想法.还要别的吗?编写模式的方式,如果你在"if(disposing)"部分没有做任何事情,它们似乎会被处理掉(稍后).评论?
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources.
}
// There are no unmanaged resources to release, but
// if we add them, they need to be released here.
}
disposed = true;
// If it is available, make the call to the
// base class's Dispose(Boolean) method
base.Dispose(disposing);
}
// implements IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
Run Code Online (Sandbox Code Playgroud)
我在这个帖子中读到Dispose(bool)中的锁是否正确,如何在包装Interop COM对象时在c#中实现dispose模式??它说,"Meta-meta评论 - 以及在你的非管理清理期间你永远不会获得锁或使用锁定是很重要的."为什么会这样?它是否也适用于非托管资源?
最后,在没有实现IDisposable的情况下,是否实现了终结器(在C#中为~MyClass())?我相信如果没有非托管资源,我会在某处读到终结器和IDisposable不是必需的(或者是可取的).但是,我确实看到在一些例子中使用没有IDisposable的终结器(参见:http://www.codeproject.com/KB/cs/idisposable.aspx作为一个例子)谢谢,戴夫
这种实现IDisposable模式的方法是一种故障安全方式:如果客户端忘记调用Dispose,运行时调用的终结器将Dispose(false)稍后调用(请注意,样本中缺少此部分).
在后一种情况下,即当Dispose终结器调用时,已经清理了托管资源,否则所讨论的对象将不具备垃圾收集的条件.
但如果是这样的话,GC.SuppressFinalize(this)调用会做什么?
运行终结器需要额外的费用.因此,如果可能,应该避免.调用GC.SuppressFinalize(this)将跳过运行终结器,因此可以更有效地对对象进行垃圾回收.
一般来说,应该避免依赖终结器,因为不能保证终结器能够运行.Raymond Chen在以下文章中描述了终结器的一些问题:
没有人得到最后两个问题(顺便说一下:每个线程只询问一个).在Dispose()中使用锁定对终结器线程非常致命.锁定可能持有的时间没有上限,当CLR注意到终结器线程卡住时,程序将在两秒钟后崩溃.而且,这只是一个bug.当另一个线程可能仍然具有对该对象的引用时,您永远不应该调用Dispose().
是的,在没有实现IDisposable的情况下实现终结器并不是闻所未闻.任何COM对象包装器(RCW)都可以.Thread类也是如此.这样做是因为调用Dispose()是不切实际的.对于COM包装器,因为无法跟踪所有引用计数.在Thread的情况下,因为必须Join()线程,以便您可以调用Dispose()失败了拥有一个线程的目的.
注意Jon Hanna的帖子.99.99%的时间实现自己的终结器确实是错误的.你有SafeHandle类来包装非托管资源.你需要一些非常模糊的东西,不能被它们包裹起来.
上述模式是雄辩地处理处置和最终确定的重叠问题的问题。
当我们处置时,我们希望:
最终确定时,我们希望:
除此之外还有以下问题:
x.Dispose();x.Dispose();您提供的代码将(一旦您添加了调用Dispose(false)管理这些问题的终结器)。在被调用的情况下,Dispose()它将清理托管和非托管成员并抑制终结,同时还防止多次调用(但它不是线程)在这方面是安全的)。在调用终结器的情况下,它将清理非托管成员。
但是,只有在同一类中组合托管和非托管关注点的反模式才需要此模式。更好的方法是通过仅与该资源相关的类来处理所有非托管资源,无论是 SafeHandle 还是您自己的单独类。那么你将有两种模式之一,其中后者很少见:
public class HasManagedMembers : IDisposable
{
/* more stuff here */
public void Dispose()
{
//if really necessary, block multiple calls by storing a boolean, but generally this won't be needed.
someMember.Dispose(); /*etc.*/
}
}
Run Code Online (Sandbox Code Playgroud)
它没有终结器,也不需要终结器。
public class HasUnmanagedResource : IDisposable
{
IntPtr _someRawHandle;
/* real code using _someRawHandle*/
private void CleanUp()
{
/* code to clean up the handle */
}
public void Dispose()
{
CleanUp();
GC.SuppressFinalize(this);
}
~HasUnmanagedResource()
{
CleanUp();
}
}
Run Code Online (Sandbox Code Playgroud)
这个版本非常罕见(甚至在大多数项目中都不会发生),其处置处理仅用于处理唯一的非托管资源,该类是该资源的包装器,并且如果处置没有发生,则终结器会执行相同的操作。
由于 SafeHandle 允许为您处理第二种模式,因此您根本不需要它。无论如何,我给出的第一个例子将处理绝大多数需要实现的情况IDisposable。示例中给出的模式只能用于向后兼容,例如当您从使用它的类派生时。