为什么C#允许您“抛出null”?

问题描述 投票:80回答:8

在编写一些特别复杂的异常处理代码时,有人问,您是否需要确保您的异常对象不为null?我说,当然不是,但是后来决定尝试一下。显然,您可以抛出null,但是在某些地方它仍会变成异常。

为什么允许这样做?

throw null;

在此摘录中,值得庆幸的是'ex'不为null,但可能是吗?

try
{
  throw null;
}
catch (Exception ex)
{
  //can ex ever be null?

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}
c# exception-handling
8个回答
90
投票

因为语言规范期望在那里有一个类型为System.Exception的表达式(因此null在该上下文中是有效的),并且不将该表达式限制为非null。通常,无法检测到该表达式的值是否为null。它必须解决停止问题。无论如何,运行时都必须处理null情况。参见:

Exception ex = null;
if (conditionThatDependsOnSomeInput) 
    ex = new Exception();
throw ex; 

当然,他们可以使抛出null文字的特定情况无效,但这无济于事,为什么要浪费规格空间并降低一致性却无济于事?

免责声明(在我被Eric Lippert打耳光之前):这是关于本设计决策背后原因的猜测。当然,我还没有参加设计会议;)


第二个问题的答案,是否在catch子句中捕获的表达式变量永远可以为null:尽管C#规范未提及其他语言是否会导致null异常传播,但它确实定义了异常的方式传播:

catch子句,如果有的话,将按照出现的顺序进行检查,以找到合适的异常处理程序。第一个catch子句

指定异常类型或异常类型的基本类型

被视为匹配项。常规catch子句被认为是任何异常类型的匹配项。 [...]对于null,粗体语句为假。因此,虽然纯粹基于C#规范所说的,我们不能说底层运行时永远不会抛出空值,但是我们可以确保即使是这种情况,也只能由通用catch {}处理条款。

对于CLI上的C#实现,我们可以参考ECMA 335规范。该文档定义了CLI内部抛出的所有异常(没有一个是null),并且提到了throw指令抛出了用户定义的异常对象。该指令的说明实际上与C#throw语句相同(除了它不将对象的类型限制为System.Exception):

说明:

throw指令将异常对象(类型O)抛出到堆栈上并清空堆栈。有关异常机制的详细信息,请参见分区I。[注意:尽管CLI允许抛出任何对象,但是CLS描述了特定的异常类,该类将用于语言互操作性。尾注]

例外:

如果System.NullReferenceExceptionobj,则抛出[null

正确性:

正确的CIL确保对象始终是null或对象引用(即类型O)。

我相信这些足以断定所捕获的异常永远不会是null


29
投票
显然,您可以抛出null,但在某些地方仍会变成异常。

5
投票
取自here

5
投票
虽然可能无法在C#中引发null,因为throw将检测到该错误并将其转换为NullReferenceException,但有可能会收到null ...我正巧正在接收该消息,这导致我的捕获(没想到'ex'为null)会遇到null引用异常,这会导致我的应用程序死亡(因为这是最后一个陷阱)。

2
投票
我认为您可能无法-当您尝试抛出null时,它不能这样做,因此它会在发生错误情况的情况下执行应做的事情,这将引发null引用异常。因此,您实际上并没有抛出null,而是没有抛出null,这会导致抛出异常。

2
投票
试图回答“ ..非常感谢'ex'不为空,但是可能会吗?”]]

由于我们可以说不能抛出为空的异常,所以catch子句也永远不必捕获为空的异常。因此,ex永远不会为空。


1
投票
[请记住,异常包括有关引发异常的详细信息。看到构造函数不知道将其扔到哪里,那么只有在throw方法将throws细节注入对象时才有意义。换句话说,CLR尝试将数据注入null,这将触发NullReferenceException。

不确定这是否正在发生,但是可以解释这种现象。


0
投票
考虑此语法:

public void Add<T> ( T item ) => throw (hashSet.Add ( item ) ? null : new Exception ( "The item already exists" ));

© www.soinside.com 2019 - 2024. All rights reserved.