在 try{} 中设置字段值并在 finally{} 中调用 base class
Setting field value in try{} and calling base class in finally{}
我在浏览 .NET Framework 源代码试图理解另一个问题时看到了这段代码(在 System.Net.PeerToPeer.Collaboration
的 PeerNearMe.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.Interrupt
或 OutOfMemoryException
.
之类的例子
你的建议实际上破坏了代码,因为你调用 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();
}
总而言之,该实现没有任何可疑之处,真的:)
我在浏览 .NET Framework 源代码试图理解另一个问题时看到了这段代码(在 System.Net.PeerToPeer.Collaboration
的 PeerNearMe.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()
:
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.Interrupt
或 OutOfMemoryException
.
你的建议实际上破坏了代码,因为你调用 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();
}
总而言之,该实现没有任何可疑之处,真的:)