Introduction
Have you seen an empty try block before? In this situation, there are some important codes in the finally block. So, why do developers use the try {} finally {} at this way?
In this article, we will talk about this usage of the try {} finally {}.
Detail
The original link is .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)- walterlv. But this blog was written in Chinese, so I translate its content to English. Waterlv is an MVP(Microsoft Most Valuable Professional), and he is good at .NET Core\WPF\.NET. Here is his Blog.
Empty try block
You can visit this link to read the source code of Exception, and in these codes, you can find some strange codes.
1 | internal void RestoreExceptionDispatchInfo(ExceptionDispatchInfo exceptionDispatchInfo) |
It’s easy to find that there is an empty try block, and some important codes are written in the finally block. So, why do Microsoft’s developers write an empty try block?
And here is the annotation for this try block:
We do this inside a
finallyclause to ensure ThreadAbort cannot be injected while we have taken the lock. This is to prevent unrelated exception restorations from getting blocked due to TAE.
That means, writing the code inside the finally clause is to avoid Thread.Abort method to interrupt the code. The execution of the Thread.Abort method is managed by CLR, and finally is also managed by CLR. And according to the CLR mechanism, finally block will not be interrupted by the Thread.Abort method.
The code in .NET core and .NET Framework are the same.
1 | // This is invoked by ExceptionDispatchInfo.Throw to restore the exception stack trace, corresponding to the original throw of the |
Constrained execution regions
This usage is introduced in Microsoft’s official document, for more detail, visit Reliability Best Practices.
Doing so instructs the just-in-time compiler to prepare all the code in the finally block before running the try block. This guarantees that the code in the finally block is built and will run in all cases. It is not uncommon in a CER to have an empty try block. Using a CER protects against asynchronous thread aborts and out-of-memory exceptions. See ExecuteCodeWithGuaranteedCleanup for a form of a CER that additionally handles stack overflows for exceedingly deep code.
So, we can use the try - finally to make a constrained execution region, then the code inside finally clause will be executed reliably.