. net捕获的异常意外为空
本文关键字:意外 异常 net | 更新日期: 2023-09-27 17:50:18
如下所示
我有一个非常奇怪的问题,捕获的异常是null。
代码使用MEF并努力报告组合错误。使用调试器,我可以看到异常被抛出(一个InvalidOperationException
),但是当它被ex
变量下面的代码中的最后一个捕获块捕获时,它是空的。这在调试器和正常执行代码时都是正确的。
static T ResolveWithErrorHandling<T>() where T : class
{
try
{
IocContainer.Compose(Settings.Default.IocConfiguration);
return IocContainer.Resolve<T>();
}
catch (ReflectionTypeLoadException ex)
{
// ... special error reporting for ReflectionTypeLoadException
}
catch (Exception ex)
{
// ex is null - that should not be possible!
// ... general error reporting for other exception types
}
return null;
}
我用注释替换的代码实际上是格式化错误消息的简单代码。没有什么奇怪的。
我已经尝试修改代码,以发现可能产生的影响:
- 如果我删除第一个捕获块(
ReflectionTypeLoadException
),在最后一个捕获块中捕获的异常不再为空。 - 如果在第一个catch块中捕获另一种异常类型,则在最后一个catch块中捕获的异常不再为空。
- 如果我为
InvalidOperationException
添加捕获块作为第一个捕获块,在该块中捕获的异常不为空。 - 如果我在两个catch块之间添加
InvalidOperationException
的catch块,则在该块中捕获的异常为null。
项目使用Code Contracts,编译器生成的代码经过后处理来检查契约。不幸的是,我还没有找到一种方法,可以在不对项目进行大手术的情况下摆脱测试目的。
我目前的解决方法是不捕获ReflectionTypeLoadException
,而是在通用异常处理程序中对ex
的类型进行分支。
这种"不可能"的行为的解释是什么?ReflectionTypeLoadException
捕获块是怎么回事?
令人尴尬的是,异常不是null,而且根据c#标准15.9.5,它不能为null。
然而,在项目中使用代码契约可能会弄乱调试器中局部变量的显示,因为编译器生成的IL代码可以被代码契约重写,因此最终的IL与调试信息略有不同步。在我的例子中,ex
变量显示为空,即使它不是。不幸的是,错误报告发生在应用程序终止之前,这意味着我认为错误报告不会被调用,因为ex
为空,ex.Message
在catch块中抛出NullReferenceException
。使用调试器,我能够"验证"ex
是空的,除了它实际上不是空的。
我的困惑是由ReflectionTypeLoadException
的catch块似乎影响调试器显示问题的事实。
感谢所有回应的人。
刚刚遇到了同样的问题。我终于发现我捕获了相同名称的不同异常,就像您所做的那样:
catch (ReflectionTypeLoadException ex)
{
// ...
}
catch (Exception ex)
{
// ex is not null!
// ...
}
都命名为'ex'。更改两个名称中的一个解决了这个问题,如:
catch (ReflectionTypeLoadException reflectionEx)
{
// ...
}
catch (Exception ex)
{
// ex is null - that should not be possible!
// ...
}
我遇到了同样的问题。在我的情况下,重命名异常变量(例如ex => ex1)允许我捕获任何异常…
您应该检查是否在某些时候,IocContainer捕获Exception ex
抛出ex.InnerException
而不检查它是否为空。
c#欣然接受throw null
,并以catch (Exception)
结束。
我遇到了同样的问题。当在调试器中查看异常时,该异常为空,即使捕获了正确类型的异常——UpdateException。我可以通过打开exception Assistant来查看异常。
一旦我关闭"执行运行时契约检查"捕获的异常不再为空。我已经积极地使用代码契约一年了,在我最近开始在这个特殊的项目中使用EF 4.1之前还没有看到这个问题——但是我不知道EF是否是一个控制变量,关于捕获的异常为null。
异常实际上不是null,这是调试器的问题。代码契约(ccrewrite)改变了IL操作码,这扰乱了调试器,因为离开了。S操作码被转换成左操作码。两个操作码有不同的大小和指令地址变化,这就是为什么当异常名称相同时调试器丢失的原因。
你可以在调试器中使用$exception来解决这个问题。
我也遇到过同样的情况。它碰巧是Eclipse调试器的一个错误。(实际上,这种情况可能只是某些调试器错误的结果。)
Eclipse重启是足够的-运行时异常变为正常,而不是null。