Where the finally is necessary?
I know how to use 开发者_如何学Pythontry-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?
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#.
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
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
.
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 than SpecificException
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 a catch
. It can still make sense to do so with a catch
, even if you're throwing an exception. Consider the case* where you want to return a value.
try
{
DoSomethingTricky();
return true;
}
catch (SpecificException ex)
{
LogException(ex);
return false;
}
finally
{
DoImportantCleanup();
}
The alternative to the above without a finally
is (in my opinion) somewhat less readable:
bool success;
try
{
DoSomethingTricky();
success = true;
}
catch (SpecificException ex)
{
LogException(ex);
success = false;
}
DoImportantCleanup();
return success;
*I do think a better example of try
/catch
/finally
is when the exception is re-thrown (using throw
, not throw ex
—but that's another topic) in the catch
block, and so the finally
is necessary as without it code after the try
/catch
would not run. This is typically accomplished with a using
statement on an IDisposable
resource, but that's not always the case. Sometimes the cleanup is not specifically a Dispose
call (or is more than just a Dispose
call).
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();
}
}
you don't necessarily use it with exceptions. You may have try/finally
to execute some clean up before every return
in the block.
The finally block always is executed irrespective of error obtained or not. It is generally used for cleaning up purposes.
For your question, the general use of Catch is to throw the error back to caller, in such cases the code is finally still executes.
The finally block will always be executed even if the exception is re-thrown in the catch block.
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
}
For example, during the process you may disable WinForm...
try
{
this.Enabled = false;
// some process
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
this.Enabled = true;
}
I am not sure how it is done in c#, but in Delphi, you will find "finally" very often. The keyword is manual memory management.
MyObject := TMyObject.Create(); //Constructor
try
//do something
finally
MyObject.Free();
end;
精彩评论