I know how to use try-catch-finally. However I do not get the advance of using finally
as I always can place the code after the try-catch block.
Is there any clear example?
Where the finally is necessary?
892 views Asked by Tray13 AtThere are 11 answers
try
{
DoSomethingImportant();
}
finally
{
ItIsRidiculouslyImportantThatThisRuns();
}
When you have a finally block, the code therein is guaranteed to run upon exit of the try. If you place code outside of the try/catch, that is not the case. A more common example is the one utilized with disposable resources when you use the using
statement.
using (StreamReader reader = new StreamReader(filename))
{
}
expands to
StreamReader reader = null;
try
{
reader = new StreamReader(filename);
// do work
}
finally
{
if (reader != null)
((IDisposable)reader).Dispose();
}
This ensures that all unmanaged resources get disposed and released, even in the case of an exception during the try
.
*Note that there are situations when control does not exit the try, and the finally would not actually run. As an easy example, PowerFailureException
.
You need a finally because you should not always have a catch:
void M()
{
var fs = new FileStream(...);
try
{
fs.Write(...);
}
finally
{
fs.Close();
}
}
The above method does not catch errors from using fs
, leaving them to the caller. But it should always close the stream.
Note that this kind of code would normally use a using() {}
block but that is just shorthand for a try/finally. To be complete:
using(var fs = new FileStream(...))
{
fs.Write(...);
} // invisible finally here
It's almost always used for cleanup, usually implicitly via a using
statement:
FileStream stream = new FileStream(...);
try
{
// Read some stuff
}
finally
{
stream.Dispose();
}
Now this is not equivalent to
FileStream stream = new FileStream(...);
// Read some stuff
stream.Dispose();
because the "read some stuff" code could throw an exception or possibly return - and however it completes, we want to dispose of the stream.
So finally
blocks are usually for resource cleanup of some kind. However, in C# they're usually implicit via a using
statement:
using (FileStream stream = new FileStream(...))
{
// Read some stuff
} // Dispose called automatically
finally
blocks are much more common in Java than in C#, precisely because of the using
statement. I very rarely write my own finally
blocks in C#.
The code put in the finally
block is executed even when:
- there are
return
statements in thetry
orcatch
block
OR - the
catch
block rethrows the exception
Example:
public int Foo()
{
try
{
MethodThatCausesException();
}
catch
{
return 0;
}
// this will NOT be executed
ReleaseResources();
}
public int Bar()
{
try
{
MethodThatCausesException();
}
catch
{
return 0;
}
finally
{
// this will be executed
ReleaseResources();
}
}
If an exception occurs (or is rethrown) in the catch-block, the code after the catch won't be executed - in contrast, code inside a finally will still be executed.
In addition, code inside a finally is even executed when the method is exited using return.
Finally is especially handy when dealing with external resources like files which need to be closed:
Stream file;
try
{
file = File.Open(/**/);
//...
if (someCondition)
return;
//...
}
catch (Exception ex)
{
//Notify the user
}
finally
{
if (file != null)
file.Close();
}
Note however, that in this example you could also use using:
using (Stream file = File.Open(/**/))
{
//Code
}
Update: This is actually not a great answer. On the other hand, maybe it is a good answer because it illustrates a perfect example of
finally
succeeding where a developer (i.e., me) might fail to ensure cleanup properly. In the below code, consider the scenario where an exception other thanSpecificException
is thrown. Then the first example will still perform cleanup, while the second will not, even though the developer may think "I caught the exception and handled it, so surely the subsequent code will run."Everybody's giving reasons to use
try
/finally
without acatch
. It can still make sense to do so with acatch
, even if you're throwing an exception. Consider the case* where you want to return a value.The alternative to the above without a
finally
is (in my opinion) somewhat less readable:*I do think a better example of
try
/catch
/finally
is when the exception is re-thrown (usingthrow
, notthrow ex
—but that's another topic) in thecatch
block, and so thefinally
is necessary as without it code after thetry
/catch
would not run. This is typically accomplished with ausing
statement on anIDisposable
resource, but that's not always the case. Sometimes the cleanup is not specifically aDispose
call (or is more than just aDispose
call).