Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Return value vs thrown Exception Design question

Let's assume we have a method handling operations in a tree hierarchical data structure located in a class handling such a structure.

Let's look closer at one of those methods:

void MoveNode(Node currentNode, Node newParentNode)
{
    /* check if new parent isn't current's child already */
     if (newParentNode.LMargin < currentNode.LMargin && newParentNode.RMargin > currentNode.RMargin)
     {
        //DO WORK
     }
     else throw new ArgumentException("New parent node cannot be current's own child");
}

MSDN states: do not throw Exceptions to control the flow !

My question: is this use of ArgumentException alright in your opinion, or would you use some kind of a return value. If so, how would you supply the error/validation message.

like image 781
theSpyCry Avatar asked Dec 12 '22 16:12

theSpyCry


2 Answers

Since the exception being thrown indicates a bug here, and it thus won't be ever thrown in a correctly working program and exception is the right choice.

What you should not do is:

try
{
   MoveNode(...)
   //Do something
}
catch(ArgumentException e)
{
  //Do something else
}

In that example you expect the exception being thrown regularly and use it to control the control flow. Catching an ArgumentException in the caller is almost always a bad idea. This kind of exception should only be caught in the top-level handler, if at all.

Personally I don't like you throwing the exception in the else clause. I prefer doing my parameter checking at the beginning of the function and throw the exception immediately afterwards. That prevents nesting the non error code within multiple if blocks.

There are three types of exceptions

  1. Asynchronous exception like StackOverflow, OutOfMemory and ThreadAborted. They can happen anywhere and can't really be handled
  2. Bug exceptions like ArgumentException, log them in the top level handler and fix the bug
  3. Expected exceptions indicating an error that can be handles locally. Typically you use these when errors are uncommon, and you can't know beforehand that an operation will cause an error. IO errors are a typical example of this.
    The cause is typically external. For example an inaccessible file, a network failure or invalid data in a file you're trying to parse.

Eric Lippert talk about these kinds of exception in a blog entry: Vexing exceptions

When to use the third kind of exception, and when to use return values is a judgment call.

like image 121
CodesInChaos Avatar answered Dec 28 '22 23:12

CodesInChaos


I don't think this is the case of "not to use exception for control the flow".

This is argument validation. The method cannot work input parameters aren't valid, so, using an exception is the best way to tell the caller that it's trying to do a bad business.

like image 23
Matías Fidemraizer Avatar answered Dec 29 '22 01:12

Matías Fidemraizer