Answers:
我喜欢用:ArgumentException
,ArgumentNullException
,和ArgumentOutOfRangeException
。
ArgumentException
–该论点有问题。ArgumentNullException
–参数为空。ArgumentOutOfRangeException
–我使用的不是很多,但是通常的用途是将索引建立到一个集合中,并给出一个很大的索引。还有其他选择,它们没有过多地关注参数本身,而是整体上对调用进行了判断:
InvalidOperationException
–该参数可能是确定的,但不是在对象的当前状态。归功于STW(以前是Yoooder)。还要投票给他答案。NotSupportedException
–传入的参数是有效的,但此实现中不支持该参数。假设有一个FTP客户端,并且您通过了一个不支持该客户端的命令。诀窍是抛出最能表达为什么无法按原样调用该方法的异常。理想情况下,应该详细说明发生错误的原因,错误原因以及解决方法。
当错误消息指向帮助,文档或其他资源时,我很喜欢。例如,Microsoft在其知识库文章中迈出了很好的第一步,例如“当我在Internet Explorer中访问网页时,为什么收到“操作中止”错误消息?” 。遇到错误时,他们会将您指向错误消息中的知识库文章。他们做得不好的是他们没有告诉你,为什么会失败。
再次感谢STW(前Yoooder)的评论。
为了回应您的跟进,我将抛出ArgumentOutOfRangeException
。查看MSDN关于此异常的说法:
ArgumentOutOfRangeException
当调用方法并且传递给该方法的至少一个参数不是null引用(Nothing
在Visual Basic中)且不包含有效值时,抛出。
因此,在这种情况下,您正在传递一个值,但这不是有效值,因为您的范围是1到12。但是,通过文档记录的方式可以清楚地知道API会抛出什么。因为尽管我可能会说ArgumentOutOfRangeException
,但是另一个开发人员可能会说ArgumentException
。简化并记录行为。
FormatException
:当参数的格式无效或复合格式的字符串格式不正确时引发的异常。
我对Josh的答案投了赞成票,但想在清单中再加上一个:
如果参数有效,则应引发System.InvalidOperationException,但对象处于不应使用参数的状态。
来自MSDN的更新:
如果因无效参数以外的原因导致调用方法失败,则使用InvalidOperationException。
假设您的对象具有PerformAction(enmSomeAction action)方法,有效的enmSomeActions是Open和Close。如果您连续两次调用PerformAction(enmSomeAction.Open),则第二次调用应引发InvalidOperationException(因为匹配有效,但不适用于控件的当前状态)
因为您已经通过防御性编程来做正确的事情,所以我要提的另一个例外是ObjectDisposedException。 如果您的对象实现IDisposable,那么您应该始终有一个跟踪已处置状态的类变量;如果您的对象已经被处置并且方法被调用,则应该引发ObjectDisposedException:
public void SomeMethod()
{
If (m_Disposed) {
throw new ObjectDisposedException("Object has been disposed")
}
// ... Normal execution code
}
更新:要回答您的后续问题:情况有点模棱两可,并且由于使用通用(不是.NET通用)意义上的通用数据类型来表示一组特定的数据而使情况变得更加复杂。枚举或其他强类型对象将是更理想的选择-但是我们并不总是拥有该控件。
我个人倾向于ArgumentOutOfRangeException并提供一条消息,指示有效值为1-12。我的理由是,当您谈论月份时,假设月份的所有整数表示形式都有效,那么您期望的值在1到12之间。如果仅某些月份(例如,具有31天的月份)有效,那么您将不会处理Range本身,而我将抛出一个表明有效值的通用ArgumentException,并且还将在方法的注释中记录它们。
根据实际值和最合适的例外情况:
ArgumentException
(值有问题)
ArgumentNullException
(参数为null,但不允许这样做)
ArgumentOutOfRangeException
(该参数的值超出有效范围)
如果不够精确,则只需从派生您自己的异常类ArgumentException
。
Yoooder的回答启发了我。如果输入在任何时候都无效,则该输入无效;而对于系统的当前状态,该输入无效,则该输入是意外的。因此,在后一种情况下,an InvalidOperationException
是一个合理的选择。
调用方法时,至少一个传递的参数不符合被调用方法的参数规范,则引发ArgumentException。ArgumentException的所有实例都应携带有意义的错误消息,描述无效的参数以及该参数的预期值范围。
对于特定类型的无效性,还存在一些子类。链接包含子类型的摘要以及何时应用子摘要。
简短答案:
都不
更长的答案:
使用Argument * Exception(在其上有产品的库(例如组件库)中除外)是一种气味。例外是处理特殊情况,而不是错误,也不是用户(即API使用者)的不足。
最长的答案:
除非编写库,否则将无效参数抛出异常是不礼貌的。
由于两个(或多个)原因,我更喜欢使用断言:
这是处理null异常的样子(显然是讽刺的):
try {
library.Method(null);
}
catch (ArgumentNullException e) {
// retry with real argument this time
library.Method(realArgument);
}
当预计情况会发生但异常时,应使用异常(发生超出用户控制范围的事情,例如IO故障)。Argument * Exception表示错误,应(通过我的看法)通过测试进行处理,并通过Debug.Assert进行辅助
顺便说一句:在这种情况下,您可能使用了Month类型,而不是int类型。C#在类型安全方面(Aspect#rulez!)不够完善,但有时您可以一起防止(或在编译时捕获)这些错误。
是的,MicroSoft在这方面是错误的。
您可以使用一个标准的ArgumentException,也可以子类化并创建自己的类。有几个特定的ArgumentException类:
http://msdn.microsoft.com/zh-cn/library/system.argumentexception(VS.71).aspx
哪一个效果最好。