10

I am confused about the order of try, catch and finally block execution.

I also want to know when should I use try-catch block and what should I put in the try-catch block? I also want to know if some exception comes in try block then if an action is taken corresponding to try block then which one is executed first catch or finally (which is always to be executed)? After the execution of these two does control return to try block or it leave it?

riQQ
  • 9,878
  • 7
  • 49
  • 66
NoviceToDotNet
  • 10,387
  • 36
  • 112
  • 166
  • Please learn to use full stops (`.`) and question marks (`?`) appropriately. I can't make any sense of your question as it currently stands. – BoltClock Nov 16 '10 at 03:45
  • The spec explained by Microsoft - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#the-try-statement – bvj Apr 03 '21 at 19:19

5 Answers5

9

If you have (note: this is not valid C#, see below for a valid example):

try {
   // ... some code: A
} catch(...) {
   // ... exception code: B
} finally {
   // finally code: C
}

Code A is going to be executed. If all goes well (i.e. no exceptions get thrown while A is executing), it is going to go to finally, so code C is going to be executed. If an exception is thrown while A is executed, then it will go to B and then finally to C.

As an example, here's a valid C# code block from http://msdn.microsoft.com/en-us/library/dszsf989.aspx:

public class EHClass
{
    void ReadFile(int index)
    {
        // To run this code, substitute a valid path from your local machine
        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();
            }
        }
        // Do something with buffer...
    }
}

The reason to use try/catch/finally is to prevent your program to fail if there is an error in some code (A in the above example). If there is a problem, you can use catch part to catch the problem and do something useful, such as inform the user, log the exception to a log file, try again or try something different that you suppose might work instead of what you tried originally.

finally is used to ensure that some cleanup is performed. E.g. in A you might try to open a file and read it. If opening succeeds, but read fails, you will have an open file dangling. What you would like in that case is to have it closed, which you would do in finally block - this block always gets executed, guaranteeing the closing of the file.

Take a look here for more info:

icyrock.com
  • 27,952
  • 4
  • 66
  • 85
  • Sir, what is the meaning of exceptions which are thrown on the "user defined conditions"? – NoviceToDotNet Nov 16 '10 at 04:25
  • Not sure I understand what you mean by "user defined conditions" - if you mean user defined exceptions, see here: http://msdn.microsoft.com/en-us/library/87cdya3t.aspx. User defined exceptions are used when none of the exceptions defined by the system give you a suitable explanation of the error you want to signal. – icyrock.com Nov 16 '10 at 13:50
  • -1: you have informed readers to do exactly the wrong thing. If there is an error in the code, then the program has already failed (and so has the programmer). The better idea is to permit the program to "fail", permit the users to complain about it, and then permit the problem to actually be fixed, not to hide your incompetance behind a catch clause and "informing the user". – John Saunders Nov 16 '10 at 19:16
  • @John Sorry, I disagree with most of what you said. First, I did not say that you should hide anything. Second, what you are saying is extremely context dependent. What would you do if you cannot connect to a database in your top-level class? I would inform the user in a catch clause. Third, exceptions are not saying there's an error in the code - of course a bunch of exceptions are runtime exceptions, nothing to do with the errors in the code. Fourth, the program certainly might not have failed completely - you could have a unimportant mail sending failure, which I would just log. – icyrock.com Nov 16 '10 at 19:21
  • @icyrock: if you can't connect to the database, inform the user, and log it, then get to a safe condition, possibly by crashing. Additionally, your mail sending failure is not unimportant unless it's a transient failure with the mail server or such, in which case, catch the specific exception. Your code does not provide an example of catching specific exceptions, so it *will* be used as an example of catching non-specific exceptions. You have not given an example of doing anything useful at all. Expand your code and maybe the downvote will come off. – John Saunders Nov 16 '10 at 19:26
  • @John Again, I disagree with most of what you said. Why is your first sentence different then what I said? I did not discuss specific or general Exception catching (it says `catch(...)`, not `catch(Exception)`), so I cannot take anything after this sentence as something wrong in my post. Thanks for sharing your thoughts, somebody else might find them useful. – icyrock.com Nov 16 '10 at 19:39
  • @icyrock: put something in between the parentheses. That's not valid C# syntax, and it _will_ be misinterpreted. Please show an example of catching a specific exception with a try/catch around specific code. Right now, you can easily be misinterpreted. – John Saunders Nov 16 '10 at 19:41
  • @John I added the example to clear up the possibility of misinterpretation. – icyrock.com Nov 16 '10 at 19:49
  • @icyrock: I'm afraid that just because an example comes from MSDN, doesn't necessarily make it something that belongs in your code. They are trying to _illustrate_ something there. They're not suggesting that you should have a `Console.WriteLine` in your code as the "handling" of an exception. – John Saunders Nov 17 '10 at 00:29
5

A try ... catch block is used to catch exceptions. In the try block you put the code that you expect may raise an exception.

If no exception occurs then the code in the try block completes as expected. If there's a finally block then that will execute next.

If an exception does occur then execution jumps to the start of the first matching catch block. Once that code is complete the finally block (if it exists) is executed. Execution does not return to the try block.

Andrew Cooper
  • 32,176
  • 5
  • 81
  • 116
4

You should almost never use try/catch.

You should only catch exceptions that you can actually correct, and only when you're expecting them. Otherwise, let the caller handle the exception - or not.

If used, any catch clauses are executed first - only one of them.

Then, finally is "finally" executed.


This has been stated better in many places, but I'll try. The following code:

try
{
    // Do something here
}
catch (Exception ex)
{
    MessageBox.Show("Friendly error message");
}

does not fix the exception. It hides the exception so that the problem will never be fixed. That code has no idea which exception was thrown, because it will catch all of them, and it does nothing to correct the problem - it just tells the user a polite fiction.

The fact of the matter is that the code above should be replaced with the following:

// Do something here

This way, if the caller of this method knows how to fix particular problems, then the caller can fix them. You will not have removed that option from the caller.

If the caller does not know how to fix the problem, then the caller should also not catch the exception.


Here is an example (from MSDN) of using exceptions in a reasonable manner. It's a modified form of the example in the documentation of the SmtpFailedRecipientsException Class.

public static void RetryIfBusy(string server)
{
    MailAddress from = new MailAddress("ben@contoso.com");
    MailAddress to = new MailAddress("jane@contoso.com");
    using (
        MailMessage message = new MailMessage(from, to)
                                  {
                                      Subject = "Using the SmtpClient class.",
                                      Body =
                                          @"Using this feature, you can send an e-mail message from an application very easily."
                                  })
    {
        message.CC.Add(new MailAddress("Notifications@contoso.com"));
        using (SmtpClient client = new SmtpClient(server) {Credentials = CredentialCache.DefaultNetworkCredentials})
        {
            Console.WriteLine("Sending an e-mail message to {0} using the SMTP host {1}.", to.Address, client.Host);
            try
            {
                client.Send(message);
            }
            catch (SmtpFailedRecipientsException ex)
            {
                foreach (var t in ex.InnerExceptions)
                {
                    var status = t.StatusCode;
                    if (status == SmtpStatusCode.MailboxBusy || status == SmtpStatusCode.MailboxUnavailable)
                    {
                        Console.WriteLine("Delivery failed - retrying in 5 seconds.");
                        System.Threading.Thread.Sleep(5000); // Use better retry logic than this!
                        client.Send(message);
                    }
                    else
                    {
                        Console.WriteLine("Failed to deliver message to {0}", t.FailedRecipient);
                            // Do something better to log the exception
                    }
                }
            }
            catch (SmtpException ex)
            {
                // Here, if you know what to do about particular SMTP status codes,
                // you can look in ex.StatusCode to decide how to handle this exception
                // Otherwise, in here, you at least know there was an email problem
            }
            // Note that no other, less specific exceptions are caught here, since we don't know
            // what do do about them
        }
    }
}

Note that this code uses try/catch to surround a small piece of code. Within that try/catch block, if an SmtpException or SmtpFailedRecipientsException is thrown, we know what to do about it. If, for instance, we were to catch IOException, we would not know what it meant, or what to do about it. Any exception you don't actually know how to correct should not be caught, except maybe to add information to the exception, log it, and rethrow.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • i am more confuse now sir, why i should not use try catch block? and if in advance i know where the exception will come then i will already correct that. Also what this your statement meaning "let the caller handle the exception - or not." – NoviceToDotNet Nov 16 '10 at 03:51
  • If you don't understand what you're doing, then try listening. Don't use it. Just leave exceptions alone. If your code is throwing an exception that it should not, then fix your code. There is very little reason to ever catch exceptions, for most developers. – John Saunders Nov 16 '10 at 19:10
  • John, I thought it was considered a very bad idea to attempt to execute code in a `catch` block? You're running a loop over calls to `Send()`. What's going to catch exceptions in there if that fails? – DonBoitnott Apr 16 '18 at 16:49
  • Nothing. Why do you want to catch exceptions in there? – John Saunders Apr 16 '18 at 16:52
  • If it was worth catching in the first place, it's worth catching there too. Otherwise, the entire example seems more academic than practical. – DonBoitnott Apr 16 '18 at 16:53
  • 1
    Nope. The purpose of catching the exception was to retry. If the retry fails, give up. – John Saunders Apr 16 '18 at 16:55
1

Here is an example:

try
{
    someFunctionThatWorks();

    functionThatThrowsAnException(); // As soon as this function throws an exception we are taken to the catch block

    anotherFunction();  // <-- This line will never get executed
}
catch(Exception e)
{
    // Here you can handle the exception, if you don't know how to handle it you should not be catching it
    // After this you will not be taken back to the try block, you will go right to the finally block
}
finally
{
    // Code here is always executed at the very end, regardless of whether an exception was thrown or not
}
tbridge
  • 1,754
  • 1
  • 18
  • 35
  • and sir, if finally itself throw some exception then what will happen? – NoviceToDotNet Nov 16 '10 at 03:54
  • If another exception is thrown in the finally block you could catch it by nesting another try ... catch ... finally, otherwise it will act as any other unhandled exception. Look at this http://stackoverflow.com/questions/481446/throws-exception-in-finally-blocks – tbridge Nov 16 '10 at 03:57
0

I'd like to elaborate a bit on this and extend @icyrock.com answer with scenario when you rethrow the exception in the catch block so it is handled lower on the execution stack...

I gave it a try with the following code:

static void Main(string[] args)
{
    try
    {
        // pick one:
        // NormalExcecution();
        // TroubleExcecution();
    }
    catch
    {
        Console.WriteLine("block D");
    }
    
    Console.ReadKey();
}

private static void NormalExcecution()
{
    try
    {
        Console.WriteLine("block A");
    }
    catch (Exception)
    {
        Console.WriteLine("block B");
        throw;
    }
    finally
    {
        Console.WriteLine("block C");
    }
}

private static void TroubleExcecution()
{
    try
    {
        Console.WriteLine("block A");
        throw new Exception();
    }
    catch (Exception)
    {
        Console.WriteLine("block B");
        throw;
    }
    finally
    {
        Console.WriteLine("block C");
    }
}

So when there is no exception in block A, then the sequence is as follows (exception handling blocks are never hit):

Block A
Block C

When there's some problem with block A, the sequence is as follows:

block A
block B
block C
block D

Another words, the occurring exception is first handled by block B, then the finally clause is executed, only after that the exception is rethrown and handled lower on the execution stack (block D).

Please mind I may be wrong with what is actually going on under the hood of the .NET framework - I just present the results I observed :)

adam.k
  • 324
  • 3
  • 14