为什么C#允许你'抛出'?

qui*_*uip 76 c# exception-handling

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

为什么允许这样做?

throw null;
Run Code Online (Sandbox Code Playgroud)

在这个片段中,幸运的是'ex'不是空的,但它可能是吗?

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

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}
Run Code Online (Sandbox Code Playgroud)

Meh*_*ari 87

因为语言规范需要一个类型的表达式System.Exception(因此,null在该上下文中是有效的),并且不会将此表达式限制为非null.通常,它无法检测该表达式的值是否null存在.它必须解决停止问题.null无论如何,运行时必须处理这个案例.看到:

Exception ex = null;
if (conditionThatDependsOnSomeInput) 
    ex = new Exception();
throw ex; 
Run Code Online (Sandbox Code Playgroud)

当然,它们可以使得null文字无效的具体情况,但这无济于事,那么为什么浪费规范空间并降低一致性几乎没有什么好处呢?

免责声明(在我被Eric Lippert打耳光之前):这是我自己对这个设计决策背后推理猜测.当然,我没有参加过设计会议;)


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

catch子句(如果有的话)按照外观的顺序进行检查,以找到异常的合适处理程序.指定异常类型的第一个catch子句或异常类型的基本类型被视为匹配.一般的catch子句被认为是任何异常类型的匹配.[...]

因为null,粗体陈述是错误的.因此,虽然纯粹基于C#规范所说的内容,但我们不能说底层运行时不会抛出null,我们可以肯定即使是这种情况,它也只能由generic catch {}子句处理.

对于CLI上的C#实现,我们可以参考ECMA 335规范.该文档定义了CLI在内部抛出的所有异常(均不是null),并提到throw指令抛出用户定义的异常对象.该指令的描述与C#throw语句几乎完全相同(除了它不限制对象的类型System.Exception):

描述:

throw指令将异常对象(类型O)抛出到堆栈上并清空堆栈.有关异常机制的详细信息,请参阅分区I.
[注意:虽然CLI允许抛出任何对象,但CLS描述了一个特定的异常类,该异常类应用于语言互操作性.结束说明]

例外:

System.NullReferenceException如果obj是的话会被抛出null.

正确性:

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

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

  • 实际上,完全有可能(在CLR中)抛出一个不从System.Exception继承的对象.据我所知,你不能在C#中做到这一点,但它可以通过IL,C++/CLR等完成.请参阅http://msdn.microsoft.com/en-us/library/ms404228.aspx了解更多信息信息. (7认同)

Ano*_*on. 26

显然,你可以抛出null,但它仍然会在某处变成异常.

尝试抛出一个null对象会导致(完全不相关)Null引用异常.

问你为什么被允许扔掉null就像问你为什么被允许这样做:

object o = null;
o.ToString();
Run Code Online (Sandbox Code Playgroud)


Fit*_*aki 5

取自这里

如果您在 C# 代码中使用此表达式,它将抛出 NullReferenceException。那是因为 throw 语句需要一个 Exception 类型的对象作为其单个参数。但是在我的例子中这个对象是空的。


Bri*_*edy 5

虽然可能无法在C#中抛出null,因为throw会检测到并将其转换为NullReferenceException,但是可能会收到null ...我碰巧现在正在接收它,这会导致我的捕获(这不是期望'ex'为null)经历一个空引用异常,然后导致我的应用程序死亡(因为那是最后一次捕获).

因此,虽然我们不能从C#中抛出null,但是netherworld可以抛出null,所以最外层的catch(Exception ex)最好准备接收它.仅供参考.

  • 有趣.你可以发布一些代码,或者可能会躲到你正在深入研究的内容中吗? (3认同)
  • 我怀疑这是一个CLR错误,或者是由于糟糕的无法验证的代码.正确的CIL只会抛出一个非null对象,或者为null(它变成NullReferenceException). (3认同)