为什么我们不要抛出这些例外?
我遇到这个MSDN页面 ,指出:
不要从你自己的源代码中故意抛出Exception , SystemException , NullReferenceException或IndexOutOfRangeException 。
不幸的是,它没有解释为什么。 我可以猜出原因,但是我希望有一个更有权威的人可以提供他们的见解。
前两个有一些明显的意义,但后两个似乎是你想要使用的(事实上,我有)。
而且,这些是唯一应该避免的例外吗? 如果有其他人,他们是什么,为什么他们也应该避免?
Exception
是所有exception的基本types,因此非常特殊。 你不应该抛出这个exception,因为它不包含任何有用的信息。 调用捕获exception的代码不能消除有意抛出的exception(来自你的逻辑)与其他完全不需要的系统exception,并指出真正的错误。
同样的原因也适用于SystemException
。 如果您查看派生types的列表,则可以看到大量其他exception具有非常不同的语义。
NullReferenceException
和IndexOutOfRangeException
是不同的types。 现在这些是非常具体的例外,所以扔他们可以罚款。 但是,你仍然不想扔这些,因为他们通常意味着你的逻辑中有一些实际的错误。 例如,空引用exception意味着你正试图访问一个null
对象的成员。 如果这在代码中是可能的,那么你应该总是显式检查null
并抛出一个更有用的exception(例如ArgumentNullException
)。 同样, IndexOutOfRangeException
在您访问无效索引时发生(在数组上 – 不是列表)。 你应该始终确保你不要这样做,并首先检查数组的边界。
还有其他一些例外情况,例如InvalidCastException
或DivideByZeroException
,这些exception是针对代码中的特定错误而引发的,通常意味着您做错了某些事情,或者您没有先检查某些无效值。 通过从代码中明确地抛出它们,只是让调用代码难以确定是由于代码中的某个错误而引发的,还是因为您决定在实现中重用它们。
当然,这些规则有一些例外(哈)。 如果你正在构build一些可能导致与现有的exception完全匹配的exception,那么可以随意使用它,特别是如果你想匹配一些内置的行为。 只要确保你select一个非常具体的exceptiontypes。
一般来说,除非你find满足你需要的(特定的)exception,否则你应该总是考虑为特定的预期exception创build你自己的exceptiontypes。 特别是在编写库代码时,这对分离exception源非常有用。
我怀疑最后2的意图是防止与预期意义的内置exception混淆。 但是,我认为如果你保留了这个例外的确切意图,那么这是正确的。 例如,如果您正在编写自定义集合,那么使用IndexOutOfRangeException
(比ArgumentOutOfRangeException
更清晰更具体的IMO)似乎是完全合理的。 虽然List<T>
可能select后者,但BCL 中至less有 41个位置(不包括数组),抛出定制的IndexOutOfRangeException
– 其中没有一个是“低级”,足以获得特殊的豁免。 所以是的,我认为你可以公正的说这个指导方针是愚蠢的。 同样, NullReferenceException
在扩展方法中也是有用的 – 如果你想保留下面的语义:
obj.SomeMethod(); // this is actually an extension method
当obj
为null
时抛出NullReferenceException
。
正如你所指出的那样,在文章创build和抛出exception(C#编程指南)的主题下的事物避免抛出exception时 ,Microsoft确实列出了System.IndexOutOfRangeException
作为exceptiontypes,不应该有意从您自己的源代码中抛出。
相比之下,在文章抛出(C#参考)中 ,微软似乎违反了自己的准则。 下面是Microsoft在其示例中包含的一种方法:
static int GetNumber(int index) { int[] nums = { 300, 600, 900 }; if (index > nums.Length) { throw new IndexOutOfRangeException(); } return nums[index]; }
所以,微软本身并没有一致性,因为它演示了抛出IndexOutOfRangeException
在其文档throw
!
这使我相信,至less在IndexOutOfRangeException
的情况下,程序员可能会抛出exceptiontypes,并被认为是可以接受的做法。
当我读到你的问题时,我问自己在什么情况下会抛出exceptiontypes为NullReferenceException
, InvalidCastException
或ArgumentOutOfRangeException
。
在我看来,当遇到这些exceptiontypes之一时,我(开发人员)感到担心编译器正在与我交谈。 所以,让你(开发者)抛出这样的exceptiontypes就相当于(编译器)卖的责任。 例如,这表明编译器现在应该允许开发人员决定一个对象是否为null
。 但做出这样的决定应该是编译器的工作。
PS:自2003年以来,我一直在发展自己的例外,所以我可以把它们扔到我想要的。 我认为这是最好的做法。
- Androidexception中使用printStackTrace()是一个坏主意?
- 重新提出exceptiontypes和消息,保留现有信息
- exception处理:抛出,抛出和Throwable
- 如果catch和finally块都抛出exception,会发生什么?
- 如何在Java中使用wait和notify?
- 为什么在调用一个函数时“抛出exception”是必要的?
- Application.ThreadException和AppDomain.CurrentDomain.UnhandledException之间有什么区别?
- 检测并排除Pandas数据框中的exception值
- 并发修改exception:添加到ArrayList