c# - 为什么 C# 允许您使用 'throw null' ?

标签 c# exception-handling

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

为什么允许这样做?

throw null;

在此代码段中,值得庆幸的是“ex”不为空,但它有可能是空的吗?

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

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}

最佳答案

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

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

当然,他们可以使抛出 null 文字的特定情况无效,但这不会有太大帮助,那么为什么要浪费规范空间并降低一致性而得不到什么好处呢?

免责声明(在我被 Eric Lippert 扇耳光之前):这是我自己对该设计决策背后原因的推测。当然,我没有参加过设计 session ;)


第二个问题的答案,捕获在 catch 子句中的表达式变量是否可以为 null:虽然 C# 规范没有说明其他语言是否会导致传播 null 异常,它确实定义了传播异常的方式:

The catch clauses, if any, are examined in order of appearance to locate a suitable handler for the exception. The first catch clause that specifies the exception type or a base type of the exception type is considered a match. A general catch clause is considered a match for any exception type. [...]

对于null,粗体语句为false。因此,虽然完全基于 C# 规范所说的内容,但我们不能说底层运行时永远不会抛出 null,我们可以确定即使是这种情况,它也只会由通用 处理捕获 {} 子句。

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

Description:

The throw instruction throws the exception object (type O) on the stack and empties the stack. For details of the exception mechanism, see Partition I.
[Note: While the CLI permits any object to be thrown, the CLS describes a specific exception class that shall be used for language interoperability. end note]

Exceptions:

System.NullReferenceException is thrown if obj is null.

Correctness:

Correct CIL ensures that object is always either null or an object reference (i.e., of type O).

我相信这些足以得出捕获的异常永远不会 null 的结论。

关于c# - 为什么 C# 允许您使用 'throw null' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2195764/

相关文章:

c# - 在 WCF (C#) 中引用服务时出现问题

javascript - 通过 document.location 在 javascript 中将文件路径作为字符串传递

spring-mvc - Spring MVC @ExceptionHandler 链接

java - 为什么 ArrayStoreException 是 RuntimeException?

performance - D 中异常处理的开销

java - 如何获取异常源对象

c# - 我可以在方法调用中强制自己短路吗?

c# - 在 Python 中使用 System.Collections.Generic.List`1[System.Byte]

memory - 中断向量中中断处理程序的地址为实际地址的+1

c# - 在处理程序中将 Json 反序列化为 Object