C# .NET 中的无效或意外参数应该抛出哪些异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/774104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What exceptions should be thrown for invalid or unexpected parameters in .NET?
提问by Even Mien
What types of exceptions should be thrown for invalid or unexpected parameters in .NET? When would I choose one instead of another?
.NET 中的无效或意外参数应引发哪些类型的异常?我什么时候会选择一个而不是另一个?
Follow-up:
跟进:
Which exception would you use if you have a function expecting an integer corresponding to a month and you passed in '42'? Would this fall into the "out of range" category even though it's not a collection?
如果您有一个函数需要一个对应于一个月的整数并且您传入了“42”,那么您会使用哪个异常?即使它不是一个集合,这是否属于“超出范围”类别?
采纳答案by JoshBerke
I like to use: ArgumentException
, ArgumentNullException
, and ArgumentOutOfRangeException
.
我喜欢用:ArgumentException
,ArgumentNullException
,和ArgumentOutOfRangeException
。
ArgumentException
– Something is wrong with the argument.ArgumentNullException
– Argument is null.ArgumentOutOfRangeException
– I don't use this one much, but a common use is indexing into a collection, and giving an index which is to large.
ArgumentException
– 论证有问题。ArgumentNullException
– 参数为空。ArgumentOutOfRangeException
– 我不经常使用这个,但一个常见的用途是索引到一个集合中,并给出一个很大的索引。
There are other options, too, that do not focus so much on the argument itself, but rather judge the call as a whole:
还有其他选项,它们不会过多关注论点本身,而是从整体上判断调用:
InvalidOperationException
– The argument might be OK, but not in the current state of the object. Credit goes to STW (previously Yoooder). Vote his answerup as well.NotSupportedException
– The arguments passed in are valid, but just not supported in this implementation. Imagine an FTP client, and you pass a command in that the client doesn't support.
InvalidOperationException
– 参数可能没问题,但不在对象的当前状态。归功于 STW(以前是 Yoooder)。也投票给他的答案。NotSupportedException
– 传入的参数有效,但在此实现中不受支持。想象一个 FTP 客户端,您传递了一个客户端不支持的命令。
The trick is to throw the exception that best expresses why the method cannot be called the way it is. Ideally, the exception should be detailed about what went wrong, why it is wrong, and how to fix it.
诀窍是抛出最能表达为什么不能按原样调用方法的异常。理想情况下,异常应该详细说明出了什么问题,为什么出错,以及如何修复它。
I love when error messages point to help, documentation, or other resources. For example, Microsoft did a good first step with their KB articles, e.g. “Why do I receive an "Operation aborted" error message when I visit a Web page in Internet Explorer?”. When you encounter the error, they point you to the KB article in the error message. What they don't do well is that they don't tell you, why specifically it failed.
我喜欢错误消息指向帮助、文档或其他资源。例如,微软在他们的知识库文章中迈出了良好的第一步,例如“为什么我在 Internet Explorer 中访问网页时会收到“操作中止”错误消息?. 当您遇到错误时,他们会将您指向错误消息中的知识库文章。他们做得不好的地方是他们没有告诉你,具体的失败原因。
Thanks to STW (ex Yoooder) again for the comments.
再次感谢 STW(前 Yoooder)的评论。
In response to your followup, I would throw an ArgumentOutOfRangeException
. Look at what MSDN says about this exception:
为了回应你的跟进,我会抛出一个ArgumentOutOfRangeException
. 看看 MSDN 是怎么说这个异常的:
ArgumentOutOfRangeException
is thrown when a method is invoked and at least one of the arguments passed to the method is not null reference (Nothing
in Visual Basic) and does not contain a valid value.
ArgumentOutOfRangeException
当调用方法并且至少一个传递给该方法的参数不是空引用(Nothing
在 Visual Basic 中)并且不包含有效值时引发。
So, in this case, you are passing a value, but that is not a valid value, since your range is 1–12. However, the way you document it makes it clear, what your API throws. Because although I might say ArgumentOutOfRangeException
, another developer might say ArgumentException
. Make it easy and document the behavior.
因此,在这种情况下,您传递的是一个值,但这不是一个有效值,因为您的范围是 1-12。但是,您记录它的方式清楚地表明您的 API 抛出了什么。因为尽管我可能会说ArgumentOutOfRangeException
,但另一位开发人员可能会说ArgumentException
。让它变得简单并记录行为。
回答by Syed Tayyab Ali
- System.ArgumentException
- System.ArgumentNullException
- System.ArgumentOutOfRangeException
- System.ArgumentException
- System.ArgumentNullException
- System.ArgumentOutOfRangeException
回答by Daniel Brückner
Depending on the actual value and what exception fits best:
根据实际值和最适合的异常:
ArgumentException
(something is wrong with the value)ArgumentNullException
(the argument is null while this is not allowed)ArgumentOutOfRangeException
(the argument has a value outside of the valid range)
ArgumentException
(值有问题)ArgumentNullException
(参数为空,而这是不允许的)ArgumentOutOfRangeException
(参数的值超出了有效范围)
If this is not precise enough, just derive your own exception class from ArgumentException
.
如果这还不够精确,只需从ArgumentException
.
Yoooder's answer enlightened me. An input is invalidif it is not valid at any time, while an input is unexpectedif it is not valid for the current state of the system. So in the later case an InvalidOperationException
is a reasonable choice.
Yoooder 的回答启发了我。如果输入在任何时候都无效,则输入是无效的,而如果输入对于系统的当前状态无效,则输入是意外的。所以在后一种情况下 anInvalidOperationException
是一个合理的选择。
回答by Ben S
参数异常:
ArgumentException is thrown when a method is invoked and at least one of the passed arguments does not meet the parameter specification of the called method. All instances of ArgumentException should carry a meaningful error message describing the invalid argument, as well as the expected range of values for the argument.
当一个方法被调用并且至少一个传递的参数不符合被调用方法的参数规范时,抛出 ArgumentException。ArgumentException 的所有实例都应携带一个有意义的错误消息,描述无效参数,以及该参数的预期值范围。
A few subclasses also exist for specific types of invalidity. The link has summaries of the subtypes and when they should apply.
对于特定类型的无效,还存在一些子类。该链接包含子类型的摘要以及它们何时适用。
回答by Scott M.
There is a standard ArgumentException that you could use, or you could subclass and make your own. There are several specific ArgumentException classes:
您可以使用一个标准的 ArgumentException,或者您可以子类化并创建自己的。有几个特定的 ArgumentException 类:
http://msdn.microsoft.com/en-us/library/system.argumentexception(VS.71).aspx
http://msdn.microsoft.com/en-us/library/system.argumentexception(VS.71).aspx
Whichever one works best.
哪个效果最好。
回答by STW
I voted for Josh's answer, but would like to add one more to the list:
我投票支持乔希的回答,但想在列表中再添加一个:
System.InvalidOperationException should be thrown if the argument is valid, but the object is in a state where the argument shouldn't be used.
如果参数有效,但对象处于不应使用该参数的状态,则应抛出 System.InvalidOperationException。
UpdateTaken from MSDN:
来自 MSDN 的更新:
InvalidOperationException is used in cases when the failure to invoke a method is caused by reasons other than invalid arguments.
InvalidOperationException 用于调用方法失败是由无效参数以外的原因引起的情况。
Let's say that your object has a PerformAction(enmSomeAction action) method, valid enmSomeActions are Open and Close. If you call PerformAction(enmSomeAction.Open) twice in a row then the second call should throw the InvalidOperationException (since the arugment was valid, but not for the current state of the control)
假设您的对象有一个 PerformAction(enmSomeAction action) 方法,有效的 enmSomeActions 是 Open 和 Close。如果您连续两次调用 PerformAction(enmSomeAction.Open) 则第二次调用应该抛出 InvalidOperationException (因为参数有效,但不适用于控件的当前状态)
Since you're already doing the right thing by programming defensively I have one other exception to mention is ObjectDisposedException. Ifyour object implements IDisposable then you should always have a class variable tracking the disposed state; if your object has been disposed and a method gets called on it you should raise the ObjectDisposedException:
由于您通过防御性编程已经在做正确的事情,因此我还有一个例外要提到的是 ObjectDisposedException。 如果您的对象实现了 IDisposable,那么您应该始终拥有一个跟踪已处理状态的类变量;如果您的对象已被处理并且在其上调用了一个方法,您应该引发 ObjectDisposedException:
public void SomeMethod()
{
If (m_Disposed) {
throw new ObjectDisposedException("Object has been disposed")
}
// ... Normal execution code
}
Update:To answer your follow-up: It is a bit of an ambiguous situation, and is made a little more complicated by a generic (not in the .NET Generics sense) data type being used to represent a specific set of data; an enum or other strongly typed object would be a more ideal fit--but we don't always have that control.
更新:回答您的后续问题:这是一个有点模棱两可的情况,并且由于用于表示特定数据集的泛型(不是 .NET 泛型意义上的)数据类型而变得更加复杂;枚举或其他强类型对象将是更理想的选择——但我们并不总是拥有这种控制权。
I would personally lean towards the ArgumentOutOfRangeException and provide a message that indicates the valid values are 1-12. My reasoning is that when you talk about months, assuming all integer representations of months are valid, then you are expecting a value in the range of 1-12. If only certain months (like months that had 31 days) were valid then you would not be dealing with a Range per-se and I would throw a generic ArgumentException that indicated the valid values, and I would also document them in the method's comments.
我个人倾向于 ArgumentOutOfRangeException 并提供一条消息,指示有效值为 1-12。我的推理是,当您谈论月份时,假设月份的所有整数表示形式都是有效的,那么您期望的值范围是 1-12。如果只有某些月份(例如有 31 天的月份)是有效的,那么您本身就不会处理 Range,我会抛出一个指示有效值的通用 ArgumentException,并且我还会在方法的注释中记录它们。
回答by THX-1138
Short answer:
Neither
简短回答:
都没有
Longer answer:
using Argument*Exception (except in a library that is a product on its on, such as component library) is a smell. Exceptions are to handle exceptional situation, not bugs, and not user's (i.e. API consumer) shortfalls.
更长的答案:
使用 Argument*Exception (除了在其上的产品的库中,例如组件库)是一种气味。异常是为了处理异常情况,而不是错误,也不是用户(即 API 消费者)的不足。
Longest answer:
Throwing exceptions for invalid arguments is rude, unless you write a library.
I prefer using assertions, for two (or more) reasons:
最长的答案:
抛出无效参数的异常是不礼貌的,除非你写一个库。
我更喜欢使用断言,有两个(或更多)原因:
- Assertions don't need to be tested, while throw assertions do, and test against ArgumentNullException looks ridiculous (try it).
- Assertions better communicate the intended use of the unit, and is closer to being executable documentation than a class behavior specification.
- You can change behavior of assertion violation. For example in debug compilation a message box is fine, so that your QA will hit you with it right away (you also get your IDE breaking on the line where it happens), while in unit test you can indicate assertion failure as a test failure.
- 断言不需要测试,而抛出断言则需要,并且针对 ArgumentNullException 的测试看起来很荒谬(试试看)。
- 断言更好地传达了单元的预期用途,并且比类行为规范更接近于可执行文档。
- 您可以更改断言违规行为。例如,在调试编译中,消息框很好,这样您的 QA 就会立即用它来打击您(您的 IDE 也会在它发生的地方中断),而在单元测试中,您可以将断言失败指示为测试失败.
Here is what handling of null exception looks like (being sarcastic, obviously):
这是处理空异常的样子(显然是讽刺):
try {
library.Method(null);
}
catch (ArgumentNullException e) {
// retry with real argument this time
library.Method(realArgument);
}
Exceptions shall be used when situation is expected but exceptional (things happen that are outside of consumer's control, such as IO failure). Argument*Exception is an indication of a bug and shall be (my opinion) handled with tests and assisted with Debug.Assert
异常应在情况可预期但异常(消费者无法控制的事情发生,例如 IO 故障)时使用。Argument*Exception 是一个错误的迹象,应该(我认为)用测试处理并用 Debug.Assert 协助
BTW: In this particular case, you could have used Month type, instead of int. C# falls short when it comes to type safety (Aspect# rulez!) but sometimes you can prevent (or catch at compile time) those bugs all together.
顺便说一句:在这种特殊情况下,您可以使用 Month 类型,而不是 int。C# 在类型安全(Aspect# rulez!)方面存在不足,但有时您可以一起防止(或在编译时捕获)这些错误。
And yes, MicroSoft is wrong about that.
是的,微软在这一点上是错误的。