Try, Catch, and Finally are the keywords used for exception handling. There are certain rules as to how we should write all these three blocks together. Usually, a "try" block is followed by "catch" block and "catch" block is followed by "finally" block. Whenever any exception is thrown by the code written inside the "try" block, that exception is handled by the respective "catch" block. However, the execution of "finally" block is little bit different. Irrespective of any exception thrown or not, the "finally" block gets executed unless we abort the system forcibly before the execution. So, this blog will explain the functionality behind the code which makes "finally" block executed by default.
Here is the code snippet that explains the use of "try", "catch", and "finally" block.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApplication1 {
- class Program {
- static void Main(string[] args) {
- try {
- var i = 0;
- var j = 10;
- Console.WriteLine(j / i);
- } catch (ArithmeticException ex) {
- Console.WriteLine("Catch block");
- } catch (Exception ex) {
- Console.WriteLine("Catch block");
-
- } finally {
- Console.WriteLine("finally block");
- }
- }
- }
- }
If we get the exception due to the code inside the "try" block, in that case, "catch" block gets executed.
Let's know why "finally" block gets executed even though there is no exception. In order to analyze this, I have gone through the IL code for the above code, as given below.
- .method private hidebysig static void Main(string[] args) cil managed {.entrypoint
-
- .maxstack 2.locals init([0] int32 i, [1] int32 j, [2] class[mscorlib] System.ArithmeticException ex, [3] class[mscorlib] System.Exception V_3)
- IL_0000: nop.try {.try {
- IL_0001: nop
- IL_0002: ldc.i4 .0
- IL_0003: stloc .0
- IL_0004: ldc.i4.s 10
- IL_0006: stloc .1
- IL_0007: ldloc .1
- IL_0008: ldloc .0
- IL_0009: div
- IL_000a: call void[mscorlib] System.Console::WriteLine(int32)
- IL_000f: nop
- IL_0010: nop
- IL_0011: leave.s IL_0033
- }
- catch [mscorlib] System.ArithmeticException {
- IL_0013: stloc .2
- IL_0014: nop
- IL_0015: ldstr "Catch block"
- IL_001a: call void[mscorlib] System.Console::WriteLine(string)
- IL_001f: nop
- IL_0020: nop
- IL_0021: leave.s IL_0033
- }
- catch [mscorlib] System.Exception {
- IL_0023: stloc .3
- IL_0024: nop
- IL_0025: ldstr "Catch block"
- IL_002a: call void[mscorlib] System.Console::WriteLine(string)
- IL_002f: nop
- IL_0030: nop
- IL_0031: leave.s IL_0033
- }
- IL_0033: nop
- IL_0034: leave.s IL_0044
- }
- finally {
- IL_0036: nop
- IL_0037: ldstr "finally block"
- IL_003c: call void[mscorlib] System.Console::WriteLine(string)
- IL_0041: nop
- IL_0042: nop
- IL_0043: endfinally
- }
- IL_0044: nop
- IL_0045: ret
- }
As per the above IL code, when we write "try", "catch" and "finally" blocks, then "try" and "catch" blocks are considered as one "try" block and the "finally" block follows that "try" block.
That’s the reason even though whether we get any exception or not, the "finally" block still gets executed almost all the time.
However, we can skip the execution of "finally" block. We can write "Environment.Exit(0)" inside the "catch" block so that the "finally" block will never get executed.