Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of throwing specific exception subclasses?

Why is it preferable to throw this Exception

Throw New DivideByZeroException("You can't divide by zero")

over this general one:

Throw New Exception("You can't divide by zero")

What advantage is gained in this particular example? The message already tell it all. Do standard subclasses that inherit from the base Exception class ever have different methods that the base? I haven't seen a case, but I must admit that I tend to throw the base Exception.

like image 549
Chad Avatar asked Oct 20 '10 17:10

Chad


4 Answers

The type of the exception allows handlers of the exception to filter it. If all you threw were exceptions of type Exception how would handlers know what exceptions to catch and which to allow to propagate up the call stack?

For example, if you always throw Exception:

void Foo(string item) {
  try {
    if (Bar(item)) { 
      Console.WriteLine("BAR!");
    }
  } catch (Exception e) {
    Console.WriteLine("Something bad?");
  }
}

bool Bar(string item) {
  if (item == null) {
    throw new Exception("Argument is null!");
  }

  return Int32.Parse(item) != 0;
}

How does the caller Foo know if a null exception occurred or if the Int32.Parse() failed? It has to check the type of the thrown exception (or do some nasty string comparison).

It's even more worrisome if you get a ThreadAbortException or OutOfMemoryException which can occur in spots you wouldn't expect an exception. In these cases if your catching code only catches Exception you may mask these (important) exceptions and cause damage to your program (or system) state.

The example code should read:

void Foo(string item) {
  try {
    if (Bar(item)) { 
      Console.WriteLine("BAR!");
    }
  } catch (ArgumentNullException ae) {
    Console.WriteLine("Null strings cannot be passed!");
  } catch (FormatException fe) {
    Console.WriteLine("Please enter a valid integer!");
  }
}

bool Bar(string item) {
  if (item == null) {
    throw new ArgumentNullException("item");
  }

  return Int32.Parse(item) != 0;
}
like image 147
Ron Warholic Avatar answered Sep 19 '22 14:09

Ron Warholic


Because you can have multiple catch statements and handle different errors differently.

For example, a DivideByZero exception might prompt the user to correct an entry, while a FileNotFound exception might alert a user that the program can't continue and close the program.

There's a nice in-depth article answering this question here: Link

like image 31
David Avatar answered Sep 17 '22 14:09

David


Rather than filtering based on the text send along the error stream, you can catch multiple types of exceptions. Each one may have a very specific way to perform a recover. The text is just there to provide the user or debugger some feedback, but the program cares about the exception type. For the same reason there is polymorphism for user created classes, there is for exceptions.

It is much easier to include multiple catch statements for different exception types than it is to parse the message text to understand what needs to be done to correctly handle the issue.

like image 21
Robolulz Avatar answered Sep 18 '22 14:09

Robolulz


Directly from MSDN - Exception Handling:

Consider catching specific exceptions when you understand why it will be thrown in a given context.

You should catch only those exceptions that you can recover from. For example, a FileNotFoundException that results from an attempt to open a non-existent file can be handled by an application because it can communicate the problem to the user and allow the user to specify a different file name or create the file. A request to open a file that generates an ExecutionEngineException should not be handled because the underlying cause of the exception cannot be known with any degree of certainty, and the application cannot ensure that it is safe to continue executing.

Do not overuse catch, as throwing another exception from within a catch block will reset the stack trace and cause the lost of important debugging information, as once again MSDN suggests:

Do not overuse catch. Exceptions should often be allowed to propagate up the call stack.

Catching exceptions that you cannot legitimately handle hides critical debugging information.

In the end, catching an exception should be for handling specific exceptions that you expect to occur under certain common scenario where you would like to log or to have some specific behaviour upon exception catch, otherwise simply throw it away, as Eric Lippert himself recommends on his blog (see Too much reuse article).

try {
    ...
} catch (Exception ex) {
    throw; // This does not reset the stack trace.
}

Instead of:

try {
    ...
} catch (Exception ex) {
    throw ex; // This does reset the stack trace.
}

Finally, an Exception does not obligatory need to offer some specificities as supplemental properties or methods or whatsoever, it is the name of it that speaks out for itself, allowing you to filter your catch upon a specific type of exception.

EDIT #1

Another interesting link about error handling on Eric Lippert's blog: Vexing exceptions.

like image 36
Will Marcouiller Avatar answered Sep 19 '22 14:09

Will Marcouiller