【发布时间】:2013-10-14 20:01:05
【问题描述】:
显然,在使用嵌套的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 永远不会被调用。
输出:
投掷:投掷(3) 投掷:投掷(2) 投掷:投掷(1) 手柄:投掷(1)我希望至少能够记录丢失的Throwing(2) 和Throwing(3)。 如何做到这一点,而不为每个 using 使用单独的 try/catch(这会破坏 using 的便利性)?
在现实生活中,这些对象通常是我无法控制的类的实例。他们可能会或可能不会抛出,但如果他们这样做,我希望可以选择观察此类异常。
这个问题是在我查看reducing the level of nested using 时出现的。有一个neat answer 建议聚合异常。有趣的是,这与嵌套 using 语句的标准行为有何不同。
[EDITED] 这个问题似乎密切相关: Should you implement IDisposable.Dispose() so that it never throws?
【问题讨论】:
-
我不认为有可能改变你的 Dispose 所以它@987654324@,是吗?我绝对明白它为什么会发生,而且我不一定会称它们为“丢失”(我认为它类似于捕获异常,然后在 catch 块中抛出一个新异常)。编辑:也许我应该问,你必须用你的
AppDomain.CurrentDomain.UnhandledException处理程序来捕获它们,还是可以接受另一种机制? -
因此,反编译表明
leave.s位于try语句生成的try块的末尾。文档指出,此运算符“无条件”将控制权转移到在执行 finally 块之后指定的标签。因此,看起来异常确实“丢失”了..因为在 finally 块执行后控制是“无条件地”转移的。 (控制转移到 finally 块之后)。 -
@Noseratio:
UnhandledException没有抓住它们,因为它们没有被处理。相反,它们会被更间接的方式吞噬。 -
@Noseratio:您愿意使用托管一次性包装器(如
LoggedDisposable)来包装一次性用品吗?您可能会像using(var loggedDisposable = new LoggedDisposable(() => new Throwing(1)) { var myThrowing = loggedDisposable.WrappedDisposable; ... }一样使用它,其中您的LoggedDisposable.Dispose方法有一个try/catch日志块,它包装了一个WrappedDisposable.Dispose调用? -
(我把上面的评论搞砸了,我会在这里修复它的重要部分以供后代使用,因为它已经过了编辑窗口并且评论是非常不正确的)我的方式看到它,当它处理
c时,它会抛出一个异常。这会导致它离开b的 using 块,从而调用b.Dispose。这又会引发一个新异常,导致它离开a的 using 块,从而调用a.Dispose引发自己的新异常...
标签: c#