在.NET中对于无效或意外的参数应该抛出什么exception?

什么types的exception应该抛出无效或意外的参数在.NET中? 我什么时候select一个而不是另一个?

跟进:

如果你有一个函数需要一个对应于一个月份的整数,并且你通过了'42',你会使用哪个exception? 即使它不是一个集合,它会落入“超出范围”范畴吗?

我喜欢使用: ArgumentExceptionArgumentNullExceptionArgumentOutOfRangeException

  • ArgumentExceptionArgumentException有问题。
  • ArgumentNullException – 参数为null。
  • ArgumentOutOfRangeException – 我不使用这个很多,但常见的用途是索引到一个集合,并提供一个大的索引。

还有其他的select,不太关注论证本身,而是把整个电话作为一个整体来判断:

  • InvalidOperationException – 参数可能正确,但不在对象的当前状态。 信贷去STW(以前Yoooder)。 投票他的答案 。
  • NotSupportedException – 传入的参数是有效的,但在此实现中不受支持。 设想一个FTP客户端,并且传递一个客户端不支持的命令。

诀窍是抛出最能expression为什么该方法不能被调用的exception。 理想情况下,应该详细说明出了什么问题,为什么出错,以及如何解决问题。

错误消息指向帮助,文档或其他资源时,我喜欢。 例如,微软对他们的知识库文章做了很好的第一步,例如“当我访问Internet Explorer的网页时 , 为什么会收到”操作中止“的错误信息? 遇到错误时,他们会将错误消息中的知识库文章指向您。 他们不擅长的是他们不告诉你,为什么它失败了。

感谢STW(前Yoooder)的意见。


为了响应你的后续,我会抛出一个ArgumentOutOfRangeException 。 看看MSDN对这个exception所说的话:

当调用一个方法并且至less有一个传递给该方法的参数不是null引用(在Visual Basic中为Nothing )并且不包含有效值时,会引发ArgumentOutOfRangeException

所以,在这种情况下,你传递一个值,但这不是一个有效的值,因为你的范围是1-12。 但是,您logging它的方式清楚地表明,您的API会抛出什么。 因为虽然我可能会说ArgumentOutOfRangeException ,另一个开发人员可能会说ArgumentException 。 使其容易和文件的行为。

取决于实际的价值和最适合的例外:

  • ArgumentException (值有问题)

  • ArgumentNullException (在不允许的情况下,参数为null)

  • ArgumentOutOfRangeException (参数的值超出有效范围)

如果这不够精确,只需从ArgumentException派生自己的exception类即可。

Yoooder的回答启发了我。 如果input在任何时候都是无效的,则input无效 ,而如果input对于系统的当前状态无效,则input是意外的。 所以在后面的例子中, InvalidOperationException是一个合理的select。

我投了Josh的回答 ,但是想再补充一下:

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

更新采取从MSDN:

InvalidOperationException用于调用方法失败的原因是由于无效参数以外的原因造成的。

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

既然你已经通过防守编程来做正确的事情,我还有一个例外就是ObjectDisposedException。 如果你的对象实现了IDisposable,那么你应该总是有一个跟踪处置状态的类variables; 如果你的对象已经被抛弃了,并且一个方法被调用,你应该抛出ObjectDisposedException:

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

更新:回答你的后续问题:这是一个模棱两可的情况,由generics(而不是.NETgenerics意义上的)数据types被用来表示一组特定的数据变得更复杂一点; 一个枚举或其他强types的对象将是一个更理想的适合 – 但我们并不总是有这种控制。

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

参数exception。

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

ArgumentException :

当一个方法被调用并且至less有一个传入的参数不符合被调用方法的参数说明时,抛出ArgumentExceptionexception。 ArgumentException的所有实例都应该携带一个描述无效参数的有意义的错误消息,以及参数值的预期范围。

对于特定types的无效,也存在一些子类。 该链接具有子types的摘要以及何时应用。

简短的回答:
也不

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

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

  • 断言不需要被testing,而抛出断言,并testing对ArgumentNullException看起来可笑(尝试它)。
  • 断言更好地传达了单元的预期用途,并且比类行为规范更接近于可执行文档。
  • 您可以更改断言违规行为。 例如在debugging编译中,一个消息框是好的,这样你的QA就会马上触发你(你也可以让你的IDE在发生的线上断开),而在unit testing中,你可以指出断言失败是一个testing失败。

这是什么处理空exception看起来像(讽刺,显然):

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

例外情况应在预期情况下使用,但例外情况(发生在消费者控制之外的事情,例如IO故障)。 参数*exception是一个错误的指示,并应(我的意见)与testing处理和协助Debug.Assert

顺便说一句:在这种情况下,你可以使用Monthtypes,而不是int。 当涉及到安全types(Aspect#rulez!)时,C#就不足为妙了,但是有时候你可以防止(或者在编译时)赶上这些错误。

是的,MicroSoft是错误的。

有一个标准的ArgumentException可以使用,或者你可以inheritance和创build自己的。 有几个特定的​​ArgumentException类:

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

无论哪一个最好。