Question

What is the difference between code like this:

string path = @"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}

finally
{
    if (file != null)
    {
        file.Close();
    }
}

and this:

string path = @"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
if (file != null)
{
    file.Close();
}

Is really finally block necessary in this construction. Why Microsoft provided such construction? It seems to be redundant. Isn't it?

Was it helpful?

Solution

Imagine if some other exception occurred that you haven't handled, e.g. an ArgumentOutOfRangeException, or if you want to rethrow the exception or throw a wrapped exception from your catch block:

  1. The first block would ensure that the file is closed regardless of whether or not an exception occurred.

  2. The second block would only close the file if either no exception occurred or an IOException occurred. It does not handle any other cases.

OTHER TIPS

The first block will close the file even if there is an uncaught exception.

The second block will close the file only if there are no exceptions, or any thrown exceptions are caught.

The first will also ensure that the file is closed if the try has a break, goto, return, continue, or any other jump construct that would cause the execution to move outside of the try block. The second doesn't, and as such it could result in the resource not being closed.

In your example, if your code throws an exception other than System.IO.IOException, your cleanup code is not guaranteed to run. With the finally block, the code within it will run no matter what type of exception is thrown.

In that case it's redundant.

It's usefull if you for example will rethrow an exception and still want some code to run after the block:

try {
  // do something dangerous
} catch(...) {
  // log the error or something
  throw; // let the exception bubble up to the caller
} finally {
  // this always runs
}
// this only runs if there was no exception

Another example is if the catch may throw an exception for a different reason:

try {
  // do something dangerous
} catch(...) {
  // handle the error
  // log the error, which may cause a different exception
} finally {
  // this runs even if the catch crashed
}
// this only runs if there was no exception, or the code in the catch worked

Simply, as code might crash for plenty of reasons you might not even know about, it's useful to put the cleanup in a finally block just to be sure that it runs whatever happens.

Imagine there was an exception inside catch{}, code inside finally would still run but if (file != null){} block will not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top