2015-11-04 57 views
4

我在浏览.NET Framework的源代码,试图了解其他的问题,我看到这个代码(PeerNearMe.csSystem.Net.PeerToPeer.Collaboration):设置字段值终于{}

private bool m_Disposed; 

protected override void Dispose(bool disposing) 
{ 
    if (!m_Disposed){ 
     try{ 
      m_Disposed = true; 
     } 
     finally{ 
      base.Dispose(disposing); 
     } 
    } 
} 

是否有任何理由将变量赋值放在try区块中?可能会以例外的方式失败吗?起初,我认为这是因为即使线程被终止,最终也会被执行:Thread.Abort()

未完成的finally块在线程被中止之前执行。

在这种情况下我期望 try块包括所有方法中:

try { 
    if (!m_disposed) 
     m_disposed = true; 
} 
finally { 
    base.Dispose(disposing) 
} 

然而they也说:

调用中止可能会阻止如果线程正在中止的线程位于代码的受保护区域中,例如catch块,finally块或约束执行区。如果调用Abort的线程持有中止线程所需的锁定,则会发生死锁。

IMO调用基类的虚拟方法是点点在这种情况下跳跃在黑暗

总之:该代码的这一点是什么?它真的试图实现什么?如果是因为Thread.Abort()那么是不是错了

编辑:如果它真的Thread.Abort()只是因为那么如果if (!m_Disposed) {之后,但之前try {发生中止它不会做其工作。请注意,Dispose()必须对多个呼叫具有弹性,并且无需执行任何操作(无论何时调用)。

+0

反讽 - MSDN建议避免_和领域,他们匈牙利命名法已经在内部完成了。 – niksofteng

+0

@dotnetkid,转换只是转换。只要整个组织遵循它,它就可以工作。 – qxg

+0

也可能是这种情况,此代码的以前版本在'm_disposed = true;'语句之前有更多语句。而try/finally块只是一个剩余的。 –

回答

4

唯一可能发生的是异步异常 - Thread.Abort就是一个例子,但也有Thread.InterruptOutOfMemoryException之类的东西。

你的建议实际上打破了代码,因为你打电话base.Dispose,无论实例是否已经处置 - 这不是意图。

现在,Thread.Abort应该只在终止一个应用程序域时使用 - 所以你不在乎m_disposed = true是否成功,该域即将被拆除。但是,您仍然关心释放任何本地资源,因为这些资源通常与进程绑定,而不是应用程序域(有时甚至超越进程或整个机器)。

finally中的代码有机会运行,即使在Thread.Abort的中间 - 没有其他方法可以确保代码在异步异常期间运行。通过在finally子句中调用base.Dispose,您确保它至少有机会执行,并且在操作过程中不会终止(但请注意,执行的所有finally子句都有固定的时间限制 - 您不想在finally中做任何复杂的事情)。

现在,在这种特殊情况下,没有真正的理由这样做 - 基类也没有做任何事情。所以它可能只是团队使用的一种常见的Dispose模式:)由于Dispose专为本地资源的确定性发布而设计,因此在finally子句中称其为绝对安全 - 它不应该做任何工作,只是释放本地资源。当然,Dispose经常被滥用 - 但你只是收获你播下的东西。

最后,不要忘了,这也正是一个using条款做了什么,所以如果你使用using,你已经在finally条款运行Dispose方法!

using (var bmp = new Bitmap()) 
{ 
    ... 
} 

被翻译成的

Bitmap bmp = null; 
try 
{ 
    bmp = new Bitmap(); 

    ... 
} 
finally 
{ 
    if (bmp != null) bmp.Dispose(); 
} 

总而言之等同,没有什么可疑的有关实现的,真的:)

+0

我同意你的一切,但是_“...打破了代码,因为......这不是这个意图。”我的意思是:Dispose()必须对多个调用有弹性。如果中止发生在if(...)之后但在尝试之前{那么基类将不会被调用。 –

+0

@AdrianoRepetti事情是,它真的没什么关系。你应该总是*在某个层次上调用'finally'块中的'Dispose' - 这是它的全部目的。这种编写'Dispose'方法本身的方式确保在'finally'内调用基类的Dispose方法 - 这不是一个坏主意,因为你不应该依赖基类的实现细节。 – Luaan

0

我不确定为什么它在试一试,因为它只是分配一个变量,也许别人可以告诉我们这个。

我想说,你的期望会采取不同的行为。将整个尝试最终放入if(!m_disposed)中意味着如果该m_disposed为true,则该对象不会调用Dispose,而您的期望将调用dispose而不管m_disposed值。

+1

这是真的,但您应该可以多次调用Dispose()而没有任何副作用,并且如果线程在if(!m_disposed)之后中止(但在m_disposed = true之前),它也会调用base.Dispose()。 –

+1

@AdrianoRepetti当你卸载一个应用程序域时,许多这些保证不再适用 - 而且这是唯一应该使用'Thread.Abort'的地方。 – Luaan

+0

@Luaan我不这么认为,否则这不是保证!如果这是该代码的目的(防止异步异常),那么它可能简单地失败。 –