从抛出的BeginInvoke时被丢弃,防止外例外 [英] Prevent outer exception from being discarded when thrown from BeginInvoke

查看:196
本文介绍了从抛出的BeginInvoke时被丢弃,防止外例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 应用程序的处理程序。 ThreadException ,但我发现异常并不总是得到传递给它正确。特别是,如果我扔从的BeginInvoke 回调的异常与 - 内的异常,我的 ThreadException 处理程序不得到的的例外 - 它只是得到的的异常

I have a handler for Application.ThreadException, but I'm finding that exceptions aren't always getting passed to it correctly. Specifically, if I throw an exception-with-inner-exception from a BeginInvoke callback, my ThreadException handler doesn't get the outer exception -- it only gets the inner exception.

示例代码:

public Form1()
{
    InitializeComponent();
    Application.ThreadException += (sender, e) =>
        MessageBox.Show(e.Exception.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
    var inner = new Exception("Inner");
    var outer = new Exception("Outer", inner);
    //throw outer;
    BeginInvoke(new Action(() => { throw outer; }));
}

如果我取消注释抛出外; 行,然后单击该按钮,然后在MessageBox表示外异常(与它的内部异常一起):

If I uncomment the throw outer; line and click the button, then the messagebox shows the outer exception (along with its inner exception):

System.Exception的:外---> System.Exception的:内蒙古结果
---内部异常堆栈跟踪---结果
结束在WindowsFormsApplication1.Form1.button1_Click(对象发件人,EventArgs的发送)在C:\svn\trunk\Code Base\Source.NET\WindowsFormsApplication1\Form1.cs:55行结果在System.Windows.Forms.Control.OnClick(EventArgs五)
结果
在System.Windows.Forms.Button.OnClick(EventArgs五)结果
在System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)结果
。在System.Windows.Forms.Control.WmMouseUp(消息和M,MouseButtons按钮,点击的Int32)在System.Windows.Forms.Control.WndProc(消息和M)结果
结果
。在System.Windows.Forms.ButtonBase.WndProc(消息&放大器;米)结果,
。在System.Windows.Forms.Button.WndProc(消息&放大器;米)搜索
。在System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息&放大器;米)结果,
。在System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息&放大器;米)结果
在System.Windows.Forms.NativeWindow.Callback(IntPtr的的HWND,味精的Int32,IntPtr的WPARAM,LPARAM的IntPtr)

System.Exception: Outer ---> System.Exception: Inner
--- End of inner exception stack trace ---
at WindowsFormsApplication1.Form1.button1_Click(Object sender, EventArgs e) in C:\svn\trunk\Code Base\Source.NET\WindowsFormsApplication1\Form1.cs:line 55
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

但是,如果抛出外; 的BeginInvoke 通话中,如上面的代码,那么 ThreadException 处理程序的只有的获取内部异常。外层的异常被前 ThreadException 剥离被调用,我得到的是:

But if the throw outer; is inside a BeginInvoke call, as in the above code, then the ThreadException handler only gets the inner exception. The outer exception gets stripped away before ThreadException is called, and all I get is:

System.Exception的:内

System.Exception: Inner

(这里有没有调用堆栈,因为从来没有抛出。在一个更现实的例子,在那里我抓到一个例外,并包好再扔,将有一个调用堆栈。)

(There's no call stack here because inner never got thrown. In a more realistic example, where I caught one exception and wrapped it to re-throw, there would be a call stack.)

同样的事情发生,如果我使用 SynchronizationContext.Current.Post 而不是的BeginInvoke :外层的例外是剥下,并在 ThreadException 处理程序只得到内部异常。

The same thing happens if I use SynchronizationContext.Current.Post instead of BeginInvoke: the outer exception is stripped off, and the ThreadException handler only gets the inner exception.

我试过缠绕例外的更多层外,在情况下,它只是剥离最外层的例外,但它并没有帮助:显然某处有沿而(e.InnerException!= NULL)E = e的线环做一些事情。的InnerException;

I tried wrapping more layers of exceptions around the outside, in case it was just stripping off the outermost exception, but it didn't help: apparently somewhere there's a loop doing something along the lines of while (e.InnerException != null) e = e.InnerException;.

我用的BeginInvoke ,因为我有代码,需要抛出一个未处理的异常由 ThreadException 马上处理,但是这个代码是 Catch中的块越往上调用堆栈(具体而言,它是作用在工作工作将捕获异常并阻止其扩散)。我试图用的BeginInvoke 延迟罚球,直到下一次消息在消息循环,处理时我不再是那个里面。我没有连接到的BeginInvoke 的特解;我只是想抛出一个未处理的异常

I'm using BeginInvoke because I've got code that needs to throw an unhandled exception to be immediately handled by ThreadException, but this code is inside a catch block higher up the call stack (specifically, it's inside the action for a Task, and Task will catch the exception and stop it from propagating). I'm trying to use BeginInvoke to delay the throw until the next time messages are processed in the message loop, when I'm no longer inside that catch. I'm not attached to the particular solution of BeginInvoke; I just want to throw an unhandled exception.

如何导致异常 - 包括其内部异常 - 达到 ThreadException 甚至当我别人的抓在 -all?

How can I cause an exception -- including its inner exception -- to reach ThreadException even when I'm inside somebody else's catch-all?

(我不能直接叫我的 ThreadException -handler方法,由于装配的依赖关系:处理程序是由EXE的启动代码大呼过瘾,而我目前的问题是在一个较低的-layer DLL)。

(I can't call my ThreadException-handler method directly, due to assembly dependencies: the handler is hooked by the EXE's startup code, whereas my current problem is in a lower-layer DLL.)

推荐答案

要做到这一点是放在一个自定义属性或<内部的异常参考的一种方式A HREF =http://msdn.microsoft.com/en-us/library/system.exception.data.aspx相对=nofollow> 数据 词典 - 即离开 的InnerException 财产无效,并进行参考一些其他的方式。

One way to do it is to put the inner-exception reference in a custom property or the Data dictionary -- i.e., leave the InnerException property null, and carry the reference some other way.

当然,这需要建立某种约定,可以投掷代码和处理代码之间共享。最好的可能会是定义一个自定义异常类与自定义属性,因为是由代码两件引用的项目。

Of course, this requires establishing some kind of convention that can be shared between the throwing code and the handling code. The best would probably be to define a custom exception class with a custom property, in a project that's referenced by both pieces of code.

示例代码(虽然它需要更多评论解释为什么它做疯狂的事情它做):

Sample code (though it needs more comments to explain why it's doing the crazy things it's doing):

public class ExceptionDecorator : Exception {
    public ExceptionDecorator(Exception exception) : base(exception.Message) {
        Exception = exception;
    }
    public Exception Exception { get; private set; }
}

// To throw an unhandled exception without losing its InnerException:
BeginInvoke(new Action(() => { throw new ExceptionDecorator(outer); }));

// In the ThreadException handler:
private void OnUnhandledException(object sender, ThreadExceptionEventArgs e) {
    var exception = e.Exception;
    if (exception is ExceptionDecorator)
        exception = ((ExceptionDecorator) exception).Exception;
    // ...
}

这篇关于从抛出的BeginInvoke时被丢弃,防止外例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆