在try{}中设置字段值,并在finally{}中调用基类
本文关键字:并在 finally 调用 基类 字段 try 设置 | 更新日期: 2023-09-27 18:20:26
我正在浏览.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也会被执行
未执行的finally块在线程中止之前执行。
在这种情况下,我希望try块包含所有方法体:
try {
if (!m_disposed)
m_disposed = true;
}
finally {
base.Dispose(disposing)
}
然而,他们也说:
如果被中止的线程位于代码的受保护区域中,例如catch块、finally块或受约束执行区域,则调用Abort的线程可能会阻塞。如果调用Abort的线程持有中止线程所需的锁,则可能发生死锁。
在这种情况下,IMO调用基类虚拟方法有点像黑暗中的跳跃。
简而言之:这段代码的意义何在?它真正想要实现什么?如果是因为Thread.Abort()
,那么这难道不是错误的吗?
EDIT:如果它真的只是因为Thread.Abort()
,那么如果中止发生在if (!m_Disposed) {
之后但在try {
之前,它就不会完成它的工作。请注意,Dispose()
必须对多个调用具有弹性,并且不执行任何操作(无论何时调用)。
唯一可能发生的是异步异常——Thread.Abort
就是一个例子,但也有类似的Thread.Interrupt
或OutOfMemoryException
。
你的建议实际上破坏了代码,因为不管实例是否已经被处理,你都会调用base.Dispose
——这不是目的。
现在,Thread.Abort
应该只在终止应用程序域时使用——所以你不在乎m_disposed = true
是否成功,反正域很快就会被拆除。然而,您仍然关心释放任何本机资源,因为这些资源通常与进程绑定,而不是与应用程序域绑定(有时,它们甚至超越进程或整个机器)。
即使在Thread.Abort
的中间,finally
中的代码也有机会运行——没有其他方法可以确保代码在异步异常期间运行。通过在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();
}
总而言之,这个实现没有什么可疑之处,真的:)
我不确定为什么它只是在尝试,因为它只分配了一个变量,也许其他人可以告诉我们。
我想说,你的期望会有所不同。将整个try finally放在if(!m_Dispose)中意味着,如果m_Dispose为true,则对象不会调用Dispose,而不管m_Dispose值如何,您的期望都会调用Dispose。