开发者

Where the finally is necessary?

开发者 https://www.devze.com 2023-02-10 03:18 出处:网络
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.

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 the try or catch 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;
0

精彩评论

暂无评论...
验证码 换一张
取 消