对于.NET中的无效或意外参数,应该抛出哪些类型的异常?我什么时候选择一个而不是另一个?
如果你有一个函数期望一个月对应的整数并且你传入'42',你会使用哪个例外?即使它不是一个集合,它会属于“超出范围”类别吗?
答案 0 :(得分:231)
我想使用:ArgumentException
,ArgumentNullException
和ArgumentOutOfRangeException
。
ArgumentException
- 这个论点出了点问题。ArgumentNullException
- 参数为空。ArgumentOutOfRangeException
- 我没有太多使用这个,但常见的用途是索引到一个集合,并给出一个很大的索引。还有其他选择,它们不太关注论证本身,而是将整个电话判断:
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
(值有问题)
ArgumentNullException
(参数为null,但不允许这样做)
ArgumentOutOfRangeException
(参数的值超出有效范围)
如果这不够精确,只需从ArgumentException
派生自己的异常类。
Yoooder的回答启发了我。输入无效如果它在任何时候都无效,而输入意外如果它对系统的当前状态无效。所以在后一种情况下,InvalidOperationException
是一个合理的选择。
答案 3 :(得分:4)
答案 4 :(得分:3)
当a抛出ArgumentException时 方法被调用并且至少有一个 传递的参数不符合 被调用的参数规范 方法。所有的实例 ArgumentException应该带有 有意义的错误消息描述 无效的论点,以及 预期的价值范围 参数。
对于特定类型的无效性,也存在一些子类。该链接包含子类型的摘要以及何时应用。
答案 5 :(得分:2)
简答:
既不
更长的回答:
使用Argument * Exception(除了在其上的产品库,例如组件库)是一种气味。例外情况是处理异常情况,而不是错误,而不是用户(即API消费者)的不足。
最长答案:
除非你写一个图书馆,否则抛出无效参数的例外是很粗鲁的
我更喜欢使用断言,原因有两个(或更多):
以下是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
无论哪一种最佳。