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

PaN*_*1Me 4 .net c# exception-handling return-value

假设我们有一个方法处理位于处理这种结构的类中的树分层数据结构中的操作.

让我们仔细看看其中一种方法:

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");
}
Run Code Online (Sandbox Code Playgroud)

MSDN声明:不要抛出异常来控制流量!

我的问题:在您看来,这种ArgumentException的使用是否正常,或者您是否会使用某种返回值.如果是这样,您将如何提供错误/验证消息.

Cod*_*aos 10

由于抛出异常表示此处存在错误,因此它不会被抛入正常工作的程序中,异常是正确的选择.

你不应该做的是:

try
{
   MoveNode(...)
   //Do something
}
catch(ArgumentException e)
{
  //Do something else
}
Run Code Online (Sandbox Code Playgroud)

在该示例中,您期望定期抛出异常并使用它来控制控制流.抓住ArgumentException呼叫者几乎总是一个坏主意.这种异常只应该在顶级处理程序中捕获,如果有的话.

我个人不喜欢你在else子句中抛出异常.我更喜欢在函数开头进行参数检查,然后立即抛出异常.这可以防止将非错误代码嵌套在多个if块中.

有三种类型的例外

  1. 异常异常,如StackOverflow,OutOfMemory和ThreadAborted.它们可以在任何地方发生,无法真正处理
  2. 像ArgumentException这样的Bug异常,将它们记录在顶级处理程序中并修复bug
  3. 预期的异常表示可以在本地处理的错误.通常,当错误不常见时使用这些,并且您无法事先知道操作将导致错误.IO错误就是一个典型的例子.
    原因通常是外部的.例如,您尝试解析的文件中存在无法访问的文件,网络故障或无效数据.

Eric Lippert在博客文章中谈到了这些异常:Vexing异常

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