As C# Specification describes:
When an exception occurs, the system searches for the nearest catch
clause that can handle the exception, as determined by the run-time type of the exception. First, the current method is searched for a lexically enclosing try
statement, and the associated catch
clauses of the try
statement are considered in order. If that fails, the method that called the current method is searched for a lexically enclosing try
statement that encloses the point of the call to the current method. This search continues until a catch
clause is found that can handle the current exception, by naming an exception class that is of the same class, or a base class, of the run-time type of the exception being thrown. A catch
clause that doesn't name an exception class can handle any exception.
Once a matching catch
clause is found, the system prepares to transfer control to the first statement of the catch
clause. Before execution of the catch
clause begins, the system first executes, in order, any finally
clauses that were associated with try
statements more nested that than the one that caught the exception.
in case of exception runtime first looks for catch
clause that can handle it, which involve executing any associated exception filters. Undiscriminating catch
block interrupt that search and make all nested finally
blocks to be executed immediately.
That can be useful when you want to prevent caller from executing arbitrary code (in form of exception filter) before finally
block. For example, when finally
block affect security context of current thread.
Also, if exception will not be caught by any catch
clause, then it will lead to thread termination. And in that case C# Specification did not provide any guaranty, that any finally
block will be executed at all.
If the search for matching catch clauses reaches the code that initially started the thread, then execution of the thread is terminated. The impact of such termination is implementation-defined.