为啥在空的 try 块中使用 try finally ?

Posted

技术标签:

【中文标题】为啥在空的 try 块中使用 try finally ?【英文标题】:Why use try finally with an empty try block?为什么在空的 try 块中使用 try finally ? 【发布时间】:2015-12-06 10:15:15 【问题描述】:

我注意到System.Threading.TimerBase.Dispose() 中的方法有一个try finally 块,但try 是空的。

try finally 与空的try 一起使用有什么价值吗?

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)

    bool status = false;
    bool bLockTaken = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try 
    
    finally 
        do 
            if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) 
                bLockTaken = true;
                try 
                    status = DeleteTimerNative(notifyObject.SafeWaitHandle);
                
                finally 
                    m_lock = 0;
                
            
            Thread.SpinWait(1);
            // yield to processor
        
        while (!bLockTaken);
        GC.SuppressFinalize(this);
    

    return status;

【问题讨论】:

System.Diagnostics.Process 也围绕第 2144 行:referencesource.microsoft.com/#System/services/monitoring/… 【参考方案1】:

来自http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/:

这种方法可以防止 Thread.Abort 调用中断 加工。的 MSDN 页面 Thread.Abort 说“未执行 finally 块在 线程被中止”。所以为了 保证您的加工 即使您的线程是 中途被某人中止 在你的线程上调用 Abort,你可以 把你所有的代码放在最后 块(另一种方法是写 “catch”块中的代码来确定 你在“尝试”之前的位置是 被 Abort 打断并从 如果你想的话就在那里)。

【讨论】:

为什么不使用msdn.microsoft.com/en-us/library/…? 因为直到 .NET 2.0 才可用 @RobFonseca-Ensor:因为Thread.BeginCriticalRegion() 不会防止线程被中止,而是告诉运行时if线程被中止,则全局状态已损坏,整个 appdomain 都将被杀。 @HansPassant: BeginCriticalSection() 在 .NET 1.x 中确实不存在,但没有因果关系,正如您所说的 因为。事实上,在 .NET 1.x 中,即使是 finally 块也可能被线程中止中断。这些机制服务于不同的目的:在 finally 中工作可防止代码中途中止,而 BeginCriticalSection() 仅向运行时声明全局状态处于危险之中。 如果开发人员在 finally 中有一段时间(true),中止是否会完成,或者在技术上是否可以无限期地忽略中止?【参考方案2】:

这是为了防止Thread.Abort 中断进程。 Documentation 这个方法说:

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

这是因为为了从错误中成功恢复,您的代码需要自行清理。由于 C# 没有 C++ 风格的析构函数,finallyusing 块是确保可靠执行此类清理的唯一可靠方法。请记住,using 块被编译器变成了这个:

try 
    ...

finally 
    if(obj != null)
        ((IDisposable)obj).Dispose();

在 .NET 1.x 中,finally 块有可能会被中止。此行为在 .NET 2.0 中已更改。

此外,空的 try 块永远不会被编译器优化掉。

【讨论】:

感谢您对 using 块的见解。 @Anton 我知道使用是最佳实践。但是出于模拟的目的,有时需要实现一个包装类,并且一次性对象成为一个私有类变量。如果我们让这个包装器是一次性的,那么 GC 不是自动处理私有类变量的处理吗? @Ozkan GC 不会自动处理任何内容。您需要实现一个终结器,通常调用Dispose(false);。 docs.microsoft.com/en-us/dotnet/standard/garbage-collection/… @Thorarin 抱歉,但你说 GC 不会自动处理(完成)是错误的。

以上是关于为啥在空的 try 块中使用 try finally ?的主要内容,如果未能解决你的问题,请参考以下文章

如果我在 Try 块中返回一个值,Finally 语句中的代码会触发吗?

try-catch- finally块中, finally块唯一不执行的情况是什么?

java中的“try - catch -finally”结构中的“finally”都有哪些用途

try-catch-finally对返回值的影响

JAVA语言如何进行异常处理,关键字throws,throw,try,catch,finally分别代表啥意义在try块中抛出异常吗

try catch finally语句块中存在return语句时的执行情况剖析