您可以在不同的线程上重新引发 .NET 异常吗?

Posted

技术标签:

【中文标题】您可以在不同的线程上重新引发 .NET 异常吗?【英文标题】:Can you rethrow a .NET exception on a different thread? 【发布时间】:2010-11-21 04:05:39 【问题描述】:

在 C# 中捕获一个线程上的异常,然后在另一个线程上重新抛出它是否合法且安全。

例如这合法吗

Exception localEx = null;

Thread mythread = new Thread()  () =>
                   
                        try
                        
                            DoSomeStuff();
                        
                        catch(Exception ex)
                        
                            localEx = ex;
                        
                    );

myThread.Start();
...
myThread.Join();

if(localEx != null)
   throw localEx;    // rethrow on the main thread

我认为这是合法的,但我很难找到任何可以证明这一点的文档。我发现的最接近的是在此处简要提及在线程之间传输异常:http://msdn.microsoft.com/en-us/library/ms229005.aspx

【问题讨论】:

你能把一个对象从一个线程传递到另一个线程吗? @Partial:当然可以。 【参考方案1】:

是的,这是合法的。异常是(一般来说)没有线程关联的描述性对象。

你最好将你的线程异常包装在一个新的异常中:

throw new Exception("Something descriptive here", localEx);

这样,localEx 中的堆栈跟踪将被保留(作为新异常的InnerException)。

【讨论】:

-1:您打算添加引文吗?如果是这样,我会投票赞成。 您的回答是“是的,这是合法的”。我认为还需要更多。您已将答案扩展到不需要反对票的程度。【参考方案2】:

你正在做的不是重新抛出。这是您碰巧在变量中的异常实例的新抛出。即使您只使用单个线程,这也是一个坏主意,因为它使异常看起来像是来自“抛出”站点。对于多个线程,我不知道任何人会如何发现线程发生了变化。

【讨论】:

【参考方案3】:

当然。在并行操作期间,System.AggregateException 被添加到 .NET 4 中专门用于该目的。

【讨论】:

【参考方案4】:

我不明白为什么它不起作用,但您需要记住您实际上并没有重新抛出异常。您正在抛出一个新异常,它恰好是同一个异常对象。因此,例如,堆栈跟踪会说它是从“throw localEx;”抛出的。而不是原始异常的来源。

【讨论】:

谢谢。是的,重新抛出是错误的词。我将使用 localEx 作为内部异常来避免您提到的调用堆栈问题。【参考方案5】:

这是合法的,它不是重新抛出,它是在另一个线程上抛出的新异常(具有相同的异常对象)

【讨论】:

【参考方案6】:

我不知道你为什么认为它不合法。如果它是非法的,编译器肯定会捕获或者运行时会抛出异常。事实上,我使用这种模式。 @John 在使用后台线程调用 Web 服务的 Windows 窗体应用程序中,我使用这种方式。然后在 Application.ThreadException ***处理程序中处理异常,记录等。无需知道异常发生在哪个线程中。

【讨论】:

以上是关于您可以在不同的线程上重新引发 .NET 异常吗?的主要内容,如果未能解决你的问题,请参考以下文章

UI线程上的.NET引发事件[重复]

可以在 Django transaction.atomic() 中捕获并重新引发异常吗?

使用不同的类型和消息重新引发异常,保留现有信息

捕获在不同线程中抛出的异常

Python在引发异常后添加重试

在 C# 中重新引发异常的正确方法是啥? [复制]