简体   繁体   中英

C# Exception Catching using try..catch blocks

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;
}

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).

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.

  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.

参数空异常的继承链

1) The specific-ness of any exception is based on its inheritence hierarchy from more generic base class exceptions.

2) You can use a general catch all as below:

try
{
    ...
}
catch (System.Exception ex)
{
    ...
}

3) Yes, this is fine although you might want to have a catch all as shown in my (2) answer after the more specific ArgumentException you already have.

1) Mostly you can tell using names. (ArgumentNullException inherits from ArgumentException, for instance). When you can't tell by name, you can look at the documentation or your object browser, and it should give you the inheritance tree.

2) Which ones you catch specifically will depend on your needs. Many would tell you that even getting an ArgumentException or ArgumentNullException means that you, as the developer, have failed to validate things higher up in your call.

3) If you've had an exception, you generally don't want to return anything- the exception itself means that your method failed to complete properly, which means you can't have good data for your return value anyway. There are exceptions to this, however, so YMMV.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM