且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

.NET返回值vs抛出异常设计问题

更新时间:2023-02-17 14:00:06

由于抛出异常表示错误在这里,它不会被抛出正确的工作程序,异常是正确的选择。



你不应该做的是:

  try 
{
MoveNode(...)
//做某事
}
catch(ArgumentException e)
{
//做别的东西
}

在该示例中,您希望定期抛出异常,并使用它来控制控制流。在调用者中捕获 ArgumentException 几乎总是一个坏主意。这种异常只能在***处理程序中被捕获(如果有的话)。



我不喜欢你在else子句中抛出异常。我更喜欢在函数开头执行我的参数检查,然后立即抛出异常。这阻止了将非错误代码嵌套在多个if(块)中。



有三种类型的异常


  1. 异步异常,如***,OutOfMemory和ThreadAborted。它们可以在任何地方发生,无法真正处理

  2. 错误异常,如ArgumentException,将其记录在***处理程序中并修复错误

  3. 预期指示可以在本地处理的错误的异常。通常,当错误不常见时使用这些,并且您不能事先知道操作将导致错误。 IO错误是一个典型的例子。

    原因通常是外部的。例如,无法访问的文件,网络故障或您尝试解析的文件中的无效数据。

Eric Lippert谈论这些博客条目中的例外情况: Vexing例外



何时使用第三种异常,何时使用返回值是判断调用。


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.

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 ***, 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.