显然,在使用嵌套的using
语句时,有些异常可能会丢失。考虑这个简单的控制台应用程序:
using System;
namespace ConsoleApplication
{
public class Throwing: IDisposable
{
int n;
public Throwing(int n)
{
this.n = n;
}
public void Dispose()
{
var e = new ApplicationException(String.Format("Throwing({0})", this.n));
Console.WriteLine("Throw: {0}", e.Message);
throw e;
}
}
class Program
{
static void DoWork()
{
// ...
using (var a = new Throwing(1))
{
// ...
using (var b = new Throwing(2))
{
// ...
using (var c = new Throwing(3))
{
// ...
}
}
}
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
// this doesn't get called
Console.WriteLine("UnhandledException:", e.ExceptionObject.ToString());
};
try
{
DoWork();
}
catch (Exception e)
{
// this handles Throwing(1) only
Console.WriteLine("Handle: {0}", e.Message);
}
Console.ReadLine();
}
}
}
每个
Throwing
实例在被处理时会触发异常,AppDomain.CurrentDomain.UnhandledException
永远不会被调用。
输出结果:
Throw: Throwing(3) Throw: Throwing(2) Throw: Throwing(1) Handle: Throwing(1)我希望至少能够记录丢失的
Throwing(2)
和Throwing(3)
。 如何做到这一点,而不需要为每个using
使用单独的try/catch
(这会破坏using
的方便性)?在现实生活中,这些对象通常是我无法控制的类的实例。它们可能会抛出异常,也可能不会,但如果它们确实这样做,我希望有一个选项来观察这些异常。
这个问题是我在查看减少嵌套
using
级别时遇到的。有一个简洁的答案建议聚合异常。有趣的是,这与嵌套using
语句的标准行为有所不同。
[编辑] 这个问题似乎与以下问题密切相关:您是否应该实现IDisposable.Dispose()以使其永远不会引发异常?
AppDomain.CurrentDomain.UnhandledException
处理程序来捕获它们,或者其他机制也可以接受? - Chris Sinclairleave.s
被放置在由using
语句生成的try
块的末尾。文档说明此操作符“无条件”转移控件到在其执行finally块之后指定的标签。因此,似乎异常确实“丢失”了...因为在执行完finally块后,“无条件”将控制权转移到finally块之后的标签处。(控制权被转移到finally块之后)。 - Simon WhiteheadUnhandledException
无法捕获它们,因为它们并没有未处理。相反,它们被更间接的方式吞噬了。 - Chris SinclairLoggedDisposable
来包装你的一次性用法吗?你可以像这样使用它:using(var loggedDisposable = new LoggedDisposable(() => new Throwing(1)) { var myThrowing = loggedDisposable.WrappedDisposable; ... }
在其中,你的LoggedDisposable.Dispose
方法中有一个try/catch
日志块,它包装了一个WrappedDisposable.Dispose
调用。 - Chris Sinclairc
时,会抛出一个异常。这导致它离开了b
的 using 块,从而调用b.Dispose
。这又引发了一个新的异常,导致它离开了a
的 using 块,从而调用a.Dispose
,并抛出自己的新异常... - Chris Sinclair