C# Exception Catching using try..catch blocks

10,612

Solution 1

Question 1:

In the MSDN documentation for each exception you can see its inheritance chain. This tells you which ones are more specific (the lower down the chain they are they more specific).

You can also see this information in the Visual Studio object browser.

Question 2:

It is good practice to catch the exceptions you can do something about. If you can't reasonably do anything with the exception, let it bubble up.

In general, tt is better to catch more specific exceptions first.

You would also want to look at the different inheritance chains and decide what exceptions you want to catch. For example, just doing:

catch(System.ArgumentException ae) { ... }

Will not catch an System.IO.SecurityException as System.IO.SecurityException doesn't inherit from System.ArgumentException.

Question 3:

Yes, this is valid syntax.

I wouldn't say good practice though. If this is an exceptional situation, it is better to let the exception to bubble up. The suggested design will cause the exception to be ignored and whoever is programming against this method need to check the return value (which they might forget).

Solution 2

A few guidelines:

  1. You can tell the 'specificity' of exceptions by looking at the inheritance heirarchy of the Exceptions on MSDN. If they derive from a common base class, the base class exception is less specific. A common example is IOException, which is the base class for several more specific exceptions related to I/O.

  2. You should generally never catch usage exceptions like ArgumentException, ArgumentNullException, NotSupportedException, etc. If these are thrown, they indicate bugs in your code that must be fixed. These should only be caught by your 'final catch' to log and perhaps format the error for friendlier display before shutting down the application.


In response to the comment:

Catching a usage exception after the fact to validate input is a bad habit, particularly if done by catching Exception (as this can mask other unexpected exception types.) It's much better to validate ahead of time. Unfortunately, this particular method (Path.GetFullPath) was not designed well with those guidelines in mind, so you need to handle ArgumentException, NotSupportedException and PathTooLongException to validate the user input. You can do this in a single catch clause like this:

try
{
     //Call Path.GetFullPath somewhere in here
}
catch (Exception ex)
{
     if (ex is ArgumentException || ex is NotSupportedException || ex is PathTooLongException)
     {
          //Your handling here
     }
     else
     {
          throw;
     }
}

You want to keep the code inside the try block as short as possible, since you don't want to inadvertantly suppress other usage exceptions besides those that can be thrown by Path.GetFullPath. You might actually want to handle each exception separately, though, as you can use the differences between them to give helpful feedback to the user as to what they did wrong.

Solution 3

  1. When you specify the name of the exception as catch(System.ArgumentNullExcpetion) then it will catch only those type. You can check the inheritance description on the exception's document page on msdn to check the more generalised exceptions are and you need worry only about those.

  2. You can catch the most general exception but sometimes the specific ones can be more useful while you are coding and debugging your program and it may help you to know what type of exception was thrown.

  3. Yes, that syntax can be used.

Inheritance chain for argument null exception

Share:
10,612
Zeos6
Author by

Zeos6

Updated on June 04, 2022

Comments

  • Zeos6
    Zeos6 almost 2 years

    I am new to C# and wanted to gain a better understanding of exception catching. These questions may be stupid noob questions. They are important to me and I apologize in advance.

    For example, in System.IO Path class, GetFullPath, there are five exceptions that can be thrown: ArgumentException, SecurityException, ArgumentNullException, NotSupportedException, and PathTooLongException. I understand that the catch blocks must be organized so that the most specific exception is caught first and the most general exception is caught last.

    Question 1: When MSDN provides information on the possible exceptions thrown by a class, how do I know which exception is the most specific and which is the least specific? In other words, how do I determine the exception order from most specific to least specific from what MSDN gives me?

    Question 2: Do I need to specifically catch all the exceptions explicitly or will using only the most generaL exception catch all the other exceptions as well? For example, still using the Path class, do I need to do ...

    try { ... }
    catch(System.ArgumentNullException ane) { ... }
    catch(System.NotSupportedException nse) { ... }
    catch(System.IO.PathTooLongException ple) { ... }
    catch(System.IO.SecurityException se) { ... }
    catch(System.ArgumentException ae) { ... }
    

    or will a simple ...

    catch(System.ArgumentException ae) { ... }
    

    catch all of the exceptions?

    Question 3: Is it correct syntax structure to do the following in a bool method ...

    try
    {
      ... ;
      return true;
    }
    catch(System.ArgumentException ae)
    {
      ... ;
      return false;
    }
    
  • Zeos6
    Zeos6 almost 13 years
    Thank you. Unfortunately I don't quite understand how to do what you suggest in 1. Re item 2, I am trying to validate a Path and catching these exceptions allows me to put up a text box to allow the user to correct their entry. So, I need tocatch them. The issue is if I can catch all of them using a single catch.
  • Zeos6
    Zeos6 almost 13 years
    Thank you. Re question 2, in my case, all the exceptions should allow the user to correct their entry. I don't want to duplicate efforts hence the question of catching them all with one catch block.
  • Zeos6
    Zeos6 almost 13 years
    Re question 1, for ArgumentException, the Inheritance Hierarchy is ... System.Object System.Exception System.SystemException System.ArgumentException More... but for SecurityException it is ... System.Object System.Exception System.SystemException System.Security.SecurityException, so how do I know which is more specific?
  • Oded
    Oded almost 13 years
    @Zeos6 - The base exception class that will catch all of the above is Exception. However, this is dangerous as it will also catch things like OutOfMemoryException. It is better to have several catch blocks with specific exceptions handled (and perhaps all calling a common function).
  • Oded
    Oded almost 13 years
    @Zeos6 - Re question 1, go look on MSDN.
  • Zeos6
    Zeos6 almost 13 years
    Ahh... lightbulb moment! So using Catch(Exception ex) { ... } will catch them all because it is the base class for alll of them. Right? I get it ... assuming I am correct here.
  • Zeos6
    Zeos6 almost 13 years
    Thank you Oded. I am all for correct coding practices but I am not sure how to avoid this general catch all in my case of validating the user's input when all the exceptions, except security which I don't catch, relate to bad input by the user and I simply want to give thenm a chance to correct the input rather than start from scratch. I am using Path class in System.IO.
  • Zeos6
    Zeos6 almost 13 years
    So, in Question 3, would it be better to take the return true out of the try block and place it at the bottom after the catch blocks to avoid others having to check the return value?
  • Oded
    Oded almost 13 years
    @Zeos6 - Looks like a reasonable way to do this, though why have a return value at all?
  • Zeos6
    Zeos6 almost 13 years
    Because it is inside a bool method and so I need to return something, do I not? Does a bool method with no return assume return true?
  • Oded
    Oded almost 13 years
    @Zeos6 - No, it has to return something. But why not make it a void instead?
  • Zeos6
    Zeos6 almost 13 years
    I see your point Oded. In my case I use this in a Bool? method. Return true tell me the path specified is OK, return null allows me to attach a default path for the file specified, and return false allows me to sanitize the input. I do, however, see the merit of using void as much as possible for methods. I will look at recoding this.
  • Zeos6
    Zeos6 almost 13 years
    Thank you. I now understand. In my case, all the exceptions will arise out of the user's bad input so I want to give them a chance to modify thir input and resubmit rather than start from scratch.
  • nbz
    nbz almost 13 years
    Yup like everyone has said, in that case you can catch an Exception
  • Zeos6
    Zeos6 almost 13 years
    I would like to thank all of you, You have been EXTREMELY helpful and generous with your time and knowledge. Thank you. All the answers were applicable and valuable to me but I am not sure how to mark this question as answered with all the entries as the answer.
  • Zeos6
    Zeos6 almost 13 years
    I already catch this Chris, using ... if(null == input || 0 == input.Length)
  • Chris Snowden
    Chris Snowden almost 13 years
    It's still always worth having a catch all exception at the end of any more specific exception handlers.
  • Zeos6
    Zeos6 almost 13 years
    Thank you. I will adopt this practice.
  • supercat
    supercat almost 13 years
    If one lets exceptions bubble up, how is the caller of something like a LoadDocument routine supposed to distinguish an ArgumentException which indicates the document was corrupt (but the application should keep on running, and use of other open documents should be unaffected) from an ArgumentException which indicates that the CPU is on fire and even trying to save open documents would likely make things even worse? For that matter, what if an IEnumerable that reads from a file encounters an I/O error? Should that kill the whole application?