2010-11-04 71 views
1

说我有这样的*的方法:当你知道你调用的方法会抛出同样的东西时,你会抛出异常吗?

public T GetItem(int index) 
{ 
    if (index < 0 || index >= _privateList.Count) 
    { 
     throw new ArgumentOutOfRangeException("index"); 
    } 

    return _privateList[index]; 
} 

你将包括throw或离开它?一方面,我觉得可以立即处理无效输入,因为这样可以让您在编写实际的实现代码时更加自信地处理您正在处理的内容。但在这种情况下,如果边界检查被省略,最终结果将大致相同(列表将抛出ArgumentOutOfRangeException而不是封闭类型)。

此外,由于上面的代码检查的东西,我,开发商,知道将反正检查(在调用_privateList[index]),看来我正在做的代码做更多的工作比它需要到上面,基本上执行两次完全相同的一组比较。

任何有关这个问题的指导,将不胜感激。 *具体而言,我正在谈论.NET(C#),但我会想象可能会问许多不同语言/框架的相同或相似问题 - 因此是“与语言无关”的标记。

回答

2

这是您在.NET框架中找到的那种代码。它在那里相当重要,源代码是(不)可用。如果没有包含参数检查,您将得到一个很难诊断的异常。它轰炸隐形代码,得出参数错误并不容易。

这与您编写的代码不太相关。但不是不存在,这取决于谁将成为代码的最终用户。如果那是你,并且你维护代码,那么你在诊断原因时会遇到一些麻烦。如果是其他人,那么重要的是他们可以随时访问源代码的精确副本。如果那是混乱的,那么不要犹豫,包括支票。

另一个考虑因素是当您部署代码的发布版本时发生的情况。没有throw语句,这个特定的代码很可能会被内联。换句话说,你不会在栈顶看到GetItem()方法。这可以使查找异常的真正源更加困难,特别是因为发布堆栈跟踪没有行号。

然后成本是相关的。在这种情况下它非常低,如果Count属性足够便宜,则可能为1纳秒或2个。但该方法所做的实际工作也非常便宜。你的测试很容易使速度降低20%。这种方法可以非常好地深深嵌入到程序的关键路径中。方法做得越多,额外测试的相关性就越小。

+0

完美的答案。感谢您从多个角度提供相关的想法。 – 2010-11-04 20:49:22

5

我尽量不要添加噪音(代码没有价值)。如果我的例外对我更有用,那么我会抛出我的异常,但如果它们完全相同,那么代码的清晰性优先。

+0

如果你正在设计一个库,正确地抛出ArgumentExceptions是一个非常好的主意。使您的课程与Microsoft设计.NET Framework的方式保持一致。开销通常不是一个问题,因为有太多的微软方法会有这样的检查,以至于应用程序无论如何都会调用它。 – 2010-11-04 23:59:38

3

在.net 4中我将为此条件定义代码合同。在早期的.net版本中,我通常不会打扰手动抛出这样的异常。

和IMO的库代码和应用程​​序代码有很大的区别。在库代码中,我更关注定义良好的错误行为,并且比我在应用程序代码中完全抛出正确的异常。

1

我永远不会抛出被调用方法抛出的异常。

但是我会(并且会!)抛出提供更多信息的异常 - 给出错误的上下文。

诊断随机异常可能会非常困难,尤其是因为通常缺少一些信息......就像堆栈跟踪本身一样。

要稍微修改您的例子:

public OrderLine GetOrderLineint index) 
{ 
    if (index < 0 || index >= _privateList.Count) 
    { 
     throw new ArgumentOutOfRangeException(
      "index", 
      "No OrderLine available at index " + index.ToString()); 
    } 

    return _privateList[index]; 
} 

这样你仍然有刚够调试信息结束。