为什么我们不要抛出这些例外?

我遇到这个MSDN页面 ,指出:

不要从你自己的源代码中故意抛出Exception , SystemException , NullReferenceException或IndexOutOfRangeException 。

不幸的是,它没有解释为什么。 我可以猜出原因,但是我希望有一个更有权威的人可以提供他们的见解。

前两个有一些明显的意义,但后两个似乎是你想要使用的(事实上,我有)。

而且,这些是唯一应该避免的例外吗? 如果有其他人,他们是什么,为什么他们也应该避免?

Exception是所有exception的基本types,因此非常特殊。 你不应该抛出这个exception,因为它不包含任何有用的信息。 调用捕获exception的代码不能消除有意抛出的exception(来自你的逻辑)与其他完全不需要的系统exception,并指出真正的错误。

同样的原因也适用于SystemException 。 如果您查看派生types的列表,则可以看到大量其他exception具有非常不同的语义。

NullReferenceExceptionIndexOutOfRangeException是不同的types。 现在这些是非常具体的例外,所以扔他们可以罚款。 但是,你仍然不想扔这些,因为他们通常意味着你的逻辑中有一些实际的错误。 例如,空引用exception意味着你正试图访问一个null对象的成员。 如果这在代码中是可能的,那么你应该总是显式检查null并抛出一个更有用的exception(例如ArgumentNullException )。 同样, IndexOutOfRangeException在您访问无效索引时发生(在数组上 – 不是列表)。 你应该始终确保你不要这样做,并首先检查数组的边界。

还有其他一些例外情况,例如InvalidCastExceptionDivideByZeroException ,这些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 

objnull时抛出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为NullReferenceExceptionInvalidCastExceptionArgumentOutOfRangeException

在我看来,当遇到这些exceptiontypes之一时,我(开发人员)感到担心编译器正在与我交谈。 所以,让你(开发者)抛出这样的exceptiontypes就相当于(编译器)卖的责任。 例如,这表明编译器现在应该允许开发人员决定一个对象是否为null 。 但做出这样的决定应该是编译器的工作。

PS:自2003年以来,我一直在发展自己的例外,所以我可以把它们扔到我想要的。 我认为这是最好的做法。