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.
Ano*_*on. 26
显然,你可以抛出null,但它仍然会在某处变成异常.
尝试抛出一个null对象会导致(完全不相关)Null引用异常.
问你为什么被允许扔掉null就像问你为什么被允许这样做:
object o = null;
o.ToString();
Run Code Online (Sandbox Code Playgroud)
虽然可能无法在C#中抛出null,因为throw会检测到并将其转换为NullReferenceException,但是可能会收到null ...我碰巧现在正在接收它,这会导致我的捕获(这不是期望'ex'为null)经历一个空引用异常,然后导致我的应用程序死亡(因为那是最后一次捕获).
因此,虽然我们不能从C#中抛出null,但是netherworld可以抛出null,所以最外层的catch(Exception ex)最好准备接收它.仅供参考.
| 归档时间: |
|
| 查看次数: |
12395 次 |
| 最近记录: |