在 try{} 中设置字段值并在 finally{} 中调用 base class

Setting field value in try{} and calling base class in finally{}

我在浏览 .NET Framework 源代码试图理解另一个问题时看到了这段代码(在 System.Net.PeerToPeer.CollaborationPeerNearMe.cs 中):

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 也会被执行

Unexecuted finally blocks are executed before the thread is aborted.

在这种情况下我希望 try 块包含所有方法体:

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

然而 they 也说:

The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region. If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur.

在这种情况下,IMO 调用基础 class 虚拟方法有点 在黑暗中跳跃

简而言之:该代码的意义何在?它真正试图实现什么?如果是因为Thread.Abort()那不就是吗?

编辑:如果真的只是因为Thread.Abort()那么如果中止发生在if (!m_Disposed) {之后但在[=20之前它就不会完成它的工作=].请注意,Dispose() 必须对多次调用具有弹性并且什么也不做(无论何时调用)。

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

我会说你的期望会有所不同。将整个 try finally 放在 if(!m_disposed) 中意味着如果 m_disposed 为真,对象将不会调用 Dispose,而无论 m_disposed 值如何,您的期望都会调用 dispose。

唯一可能发生的是异步异常 - Thread.Abort 是一个例子,但也有 Thread.InterruptOutOfMemoryException.

之类的例子

你的建议实际上破坏了代码,因为你调用 base.Dispose 不管实例是否已经被处置 - 这不是本意。

现在,Thread.Abort 只应在终止应用程序域时使用 - 因此您不必关心 m_disposed = true 是否成功,反正该域很快就会被拆除。但是,您仍然关心释放任何本机资源,因为它们通常与进程相关,而不是应用程序域(有时,它们甚至超越进程或整个机器)。

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

中做任何复杂的事情

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

最后,不要忘记这也是 using 子句的作用,所以如果您使用 using,您已经 运行 宁 Dispose 方法在 finally 子句中!

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

翻译成等同于

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

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

总而言之,该实现没有任何可疑之处,真的:)