.NET中的无效或意外参数应该抛出哪些异常?

时间:2009-04-21 19:03:41

标签: c# .net vb.net exception

对于.NET中的无效或意外参数,应该抛出哪些类型的异常?我什么时候选择一个而不是另一个?

随访:

如果你有一个函数期望一个月对应的整数并且你传入'42',你会使用哪个例外?即使它不是一个集合,它会属于“超出范围”类别吗?

7 个答案:

答案 0 :(得分:231)

我想使用:ArgumentExceptionArgumentNullExceptionArgumentOutOfRangeException

还有其他选择,它们不太关注论证本身,而是将整个电话判断:

  • InvalidOperationException - 参数可能没问题,但不在对象的当前状态。 信用转到STW(以前是Yoooder)。也可以投票his answer
  • NotSupportedException - 传入的参数有效,但在此实现中不受支持。想象一下FTP客户端,并传递一个客户端不支持的命令。

诀窍是抛出最能表达为什么不能按原样调用方法的异常。理想情况下,应该详细说明出现了什么问题,错误原因以及解决方法。

我喜欢错误消息指向帮助,文档或其他资源。例如,微软在他们的知识库文章中做了很好的第一步,例如“Why do I receive an "Operation aborted" error message when I visit a Web page in Internet Explorer?”。当您遇到错误时,他们会将您指向错误消息中的知识库文章。他们做得不好的是,他们没有告诉你,为什么特别失败。

再次感谢STW(前Yoooder)的评论。


为了回应你的后续行动,我会抛出ArgumentOutOfRangeException。看看MSDN对此例外的看法:

  抛出

ArgumentOutOfRangeException   什么时候调用一个方法,至少   其中一个参数传递给了   方法不为null   引用(Visual Basic中的Nothing)   并且不包含有效值。

因此,在这种情况下,您传递的是值,但这不是有效值,因为您的范围是1-12。但是,您记录它的方式清楚地说明了您的API抛出的内容。因为虽然我可能会说ArgumentOutOfRangeException,但另一位开发人员可能会说ArgumentException。简化并记录行为。

答案 1 :(得分:41)

我投票赞成Josh's answer,但又希望在列表中添加一个:

如果参数有效,则应抛出System.InvalidOperationException,但该对象处于不应使用该参数的状态。

更新取自MSDN:

  

使用InvalidOperationException   无法调用时的情况   方法是由其他原因引起的   无效的论点。

假设你的对象有一个PerformAction(enmSomeAction动作)方法,有效的enmSomeActions是Open和Close。如果你连续两次调用PerformAction(enmSomeAction.Open),那么第二次调用应抛出InvalidOperationException(因为arugment有效,但不是控件的当前状态)

由于你已经通过防御性编程做了正确的事情,我还有一个例外是ObjectDisposedException。 如果你的对象实现了IDisposable,那么你应该总是有一个跟踪处置状态的类变量;如果您的对象已被释放并且方法被调用,则应该引发ObjectDisposedException:

public void SomeMethod()
{
    If (m_Disposed) {
          throw new ObjectDisposedException("Object has been disposed")
     }
    // ... Normal execution code
}

更新:回答您的后续行动:这有点模棱两可,并且由于通用(不是.NET Generics意义上的)数据类型而变得更加复杂用于表示一组特定的数据;一个枚举或其他强类型对象将是一个更理想的适合 - 但我们并不总是有这种控制。

我个人倾向于ArgumentOutOfRangeException并提供一条消息,指示有效值为1-12。我的理由是,当你谈论几个月时,假设所有月的整数表示都是有效的,那么你期望的值在1-12范围内。如果只有某些月份(比如有31天的月份)有效,那么你就不会处理一个Range per-se,我会抛出一个表示有效值的泛型ArgumentException,我也会在方法的注释中记录它们。

答案 2 :(得分:35)

取决于实际值和最适合的异常:

如果这不够精确,只需从ArgumentException派生自己的异常类。

Yoooder的回答启发了我。输入无效如果它在任何时候都无效,而输入意外如果它对系统的当前状态无效。所以在后一种情况下,InvalidOperationException是一个合理的选择。

答案 3 :(得分:4)

argument exception.

  • System.ArgumentException
  • System.ArgumentNullException
  • System.ArgumentOutOfRangeException

答案 4 :(得分:3)

ArgumentException

  

当a抛出ArgumentException时   方法被调用并且至少有一个   传递的参数不符合   被调用的参数规范   方法。所有的实例   ArgumentException应该带有   有意义的错误消息描述   无效的论点,以及   预期的价值范围   参数。

对于特定类型的无效性,也存在一些子类。该链接包含子类型的摘要以及何时应用。

答案 5 :(得分:2)

简答:
既不

更长的回答:
使用Argument * Exception(除了在其上的产品库,例如组件库)是一种气味。例外情况是处理异常情况,而不是错误,而不是用户(即API消费者)的不足。

最长答案:
除非你写一个图书馆,否则抛出无效参数的例外是很粗鲁的 我更喜欢使用断言,原因有两个(或更多):

  • 断言不需要测试, 抛出断言,并测试 反对ArgumentNullException看起来 荒谬(尝试一下)。
  • 断言更好地传达了单位的预期用途,并且是 更接近可执行 文档而不是类行为 规格。
  • 您可以更改断言违规的行为。例如,在调试编译中,一个消息框很好,这样你的QA就会立即用它来打你(你的IDE也会在它发生的地方突破),而在单元测试中,你可以指示断言失败是一个测试失败

以下是null异常的处理方式(显然是讽刺的):

try {
    library.Method(null);
}
catch (ArgumentNullException e) {
    // retry with real argument this time
    library.Method(realArgument);
}

当情况出现但异常时(例如IO故障之外的事情发生在消费者无法控制之外),应使用例外情况。 参数*异常是一个错误的指示,应该(我的意见)处理测试并辅助Debug.Assert

BTW:在这种特殊情况下,您可以使用Month类型而不是int。 C#在类型安全方面不尽如人意(Aspect#rulez!)但有时你可以防止(或在编译时捕获)这些错误。

是的,MicroSoft错了。

答案 6 :(得分:0)

您可以使用标准的ArgumentException,或者您可以创建自己的子类。有几个特定的​​ArgumentException类:

http://msdn.microsoft.com/en-us/library/system.argumentexception(VS.71).aspx

无论哪一种最佳。