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
finally
clause 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.