关于C#Dispose模式的具体问题
关于C#中的Dispose模式,我有几个基本问题 在下面的代码片段中,这似乎是实现dispose模式的标准方法,您会注意到,如果disposing为false,则不会处理托管资源。如何/何时处理?GC是否会在以后处理托管资源?但是如果是这样,那么GG.SuppressFinalize(这个)调用做什么呢?有人能给我举一个处置托管资源的例子吗?脱钩事件浮现在脑海中。还有别的吗?按照模式的编写方式,如果您在“if(disposing)”部分中什么都不做,它们似乎会(稍后)被处理掉。评论关于C#Dispose模式的具体问题,c#,dispose,idisposable,C#,Dispose,Idisposable,关于C#中的Dispose模式,我有几个基本问题 在下面的代码片段中,这似乎是实现dispose模式的标准方法,您会注意到,如果disposing为false,则不会处理托管资源。如何/何时处理?GC是否会在以后处理托管资源?但是如果是这样,那么GG.SuppressFinalize(这个)调用做什么呢?有人能给我举一个处置托管资源的例子吗?脱钩事件浮现在脑海中。还有别的吗?按照模式的编写方式,如果您在“if(disposing)”部分中什么都不做,它们似乎会(稍后)被处理掉。评论 protec
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);
}
我在这个线程中读到的关于Dispose(bool)中的锁的内容是真的吗?它说,“元注释——同样重要的是,在非托管清理过程中永远不要获取锁或使用锁。”这是为什么?它是否也适用于非托管资源
最后,on是否曾经在不实现IDisposable的情况下实现过终结器(~MyClass()在C#中)?我相信我在某个地方读到,如果没有非托管资源,那么终结器和IDisposable是不必要的(或不可取的)。但是,在一些示例中,我确实看到了在没有IDisposable的情况下使用终结器(请参见:作为一个示例)
谢谢
Dave这种实现
IDisposable
模式的方法是一种故障安全的方法:如果客户端忘记调用Dispose
,运行时调用的终结器稍后将调用Dispose(false)
(请注意,示例中缺少此部分)
在后一种情况下,即当终结器调用Dispose
时,托管资源将已被清理,因为否则所涉及的对象将不符合垃圾收集的条件
但是如果是这样的话,GC.SuppressFinalize(这个)调用做什么呢
运行终结器会带来额外的成本。因此,如果可能的话,应该避免。调用GC.SuppressFinalize(this)
将跳过运行终结器,因此可以更有效地对对象进行垃圾收集
一般来说,应该避免依赖终结器,因为不能保证终结器将运行。Raymond Chen在以下帖子中描述了终结器的一些问题:
…您会注意到,如果disposing为false,则不会处理托管资源。如何/何时处理
您没有将其包含在示例中,但该类型通常会有一个析构函数,该析构函数将调用Dispose(false)
。因此,当disposing
为false
时,您“知道”您正在进行终结器调用,因此不应该*访问任何托管资源,因为它们可能已经被终结
GC终结过程只确保终结器被调用,而不是按照它们被调用的顺序
GG.SuppressFinalize(这个)调用做什么
它阻止GC将您的对象添加到终结队列,并最终调用object.Finalize()
(即您的析构函数)。这是一种性能优化,仅此而已
按照模式的编写方式,如果您在“if(disposing)”部分中不做任何操作,它们似乎会(稍后)被处理掉
也许;这取决于类型的编写方式。IDisposable
惯用语的一个要点是“确定性终结”,即说“我希望您的资源现在就被释放”,并使其具有某种意义。如果“忽略”Dispose=true
块,并且不“转发”Dispose()
调用,则会发生以下两种情况之一:
Dispose()
Dispose()
抛出异常。使用锁可能会导致异常或死锁,这两种情况都是破坏一天的好方法。:-)
on是否曾经在没有实现IDisposable的情况下实现过终结器(~MyClass()在C#中)
可以,但这会被认为是糟糕的样式。处理对象的正常方式是调用它的
Dispose()
方法。这样做后,SuppressFinalize
调用将对象从终结器队列中移除,使其成为一个可以轻松进行垃圾收集的常规托管对象
只有当代码未能正确处理对象时,才会使用终结器。然后终结器调用
Dispose(false)
,以便对象至少可以尝试清理非托管资源。由于对象引用的任何托管对象在此阶段可能已被垃圾收集,因此对象不应尝试清理它们。而应尝试通过模式了解处置,您可能希望将事情反过来,并尝试了解为什么该模式是基于CLR基础知识和IDisposable接口的预期用途以这种方式实现的。这里有一个非常好的介绍,可以回答您的所有问题(还有一些您不想问的问题)。上面描述的模式是雄辩地处理处置和最终确定的重叠问题
在处置时,我们希望:
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.*/
}
}
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();
}
}