The finally block
When you leave the kitchen, turn off the stove, whatever happens. You may have finished cooking, been called to the phone or run out at the fire alarm. Either way, the stove goes off on every way out of the kitchen.
In a program, you can break this rule without noticing. Look at what happens to the stove when an exception occurs in try:
Console.WriteLine("Stove on"); // Stove on
try
{
int minutes = int.Parse("x");
Console.WriteLine("Cooking for " + minutes);
Console.WriteLine("Stove off");
}
catch (FormatException)
{
Console.WriteLine("Not a number"); // Not a number
}int.Parse("x") throws an exception, and execution jumps straight to catch. The two lines below are skipped, and Stove off is not printed: the stove was left on.
You could move Stove off after the try and catch blocks. That would help here, but not always. A method may leave early through return, and an exception of another class goes right past the catch. Then the line after the blocks does not run again.
A third block: finally
For such a rule, C# has a third block. A finally block goes after catch or right after try, and it always runs when execution leaves try:
Console.WriteLine("Stove on"); // Stove on
try
{
int minutes = int.Parse("x");
Console.WriteLine("Cooking for " + minutes);
}
catch (FormatException)
{
Console.WriteLine("Not a number"); // Not a number
}
finally
{
Console.WriteLine("Stove off"); // Stove off
}Let's go through the program step by step:
Stove onis printed.int.Parse("x")throws aFormatException, and the rest oftryis skipped.catchprintsNot a number.finallyprintsStove off.
If you replace "x" with "5", there is no exception. The program prints Stove on, Cooking for 5 and Stove off: finally runs this time too.
After return and an exception
You can also leave try early: through return, or through an exception the method does not catch itself. finally runs then as well, right before the method is left.
Interviewers like to ask: "Does finally run if try has a return?" The answer is yes. finally is skipped only when the program ends at once, as with the StackOverflowException from the methods theme.
In the program below, the method Read leaves try twice: the first time through return, the second through an exception. Press "Next step" and watch when Stove off is printed.
1Console.WriteLine(Read("5"));2try3{4 Console.WriteLine(Read("x"));5}6catch (FormatException)7{8 Console.WriteLine("Caught");9}10 11int Read(string text)12{13 try14 {15 return int.Parse(text);16 }17 finally18 {19 Console.WriteLine("Stove off");20 }21}
Main calls Read("5") and waits for a number to print.
The program prints Stove off twice, both times before execution returns to Main. Let's look at both ways out.
Leaving through return
return int.Parse(text); first computes the number 5 and remembers it. Then finally runs, and only after that does the method return 5. That is why Stove off is printed before Main prints 5.
Leaving through an exception
For "x", the exception is thrown inside the try of Read. Read has no catch of its own, so the exception goes on to Main, but finally runs on the way. Only then does the catch in Main print Caught.
Here the stove analogy falls short. After turning off the stove, you can still change your mind and stay in the kitchen. A finally block does not cancel the exit and does not catch the exception: after it, Read still returns 5 or passes the exception on.
Common mistake
The goal was a method that returns 0 on an error, so return was written right in finally, since it always runs:
Console.WriteLine(Read("5"));
int Read(string text)
{
try
{
return int.Parse(text);
}
finally
{
return 0; // ✗
}
}error CS0157: Control cannot leave the body of a finally clauseThe program does not compile: you cannot leave the body of finally through return. A finally block only tidies up, and a default value can be returned from catch: catch (FormatException) { return 0; }.
Key points
finallyruns on every way out oftry: after the normal end, aftercatch, afterreturnand after an exception that goes on.- With
return, the value is computed beforefinally, and the method returns it after. finallyholds what must be done in any case: turn off the stove, close a file.- A
returninfinallyitself is forbidden: errorCS0157.