在线程中捕获System.Exception

时间:2011-04-04 12:06:47

标签: c# .net exception exception-handling

我知道捕获System.Exception不是好习惯,除非在应用程序的顶层。线程怎么样?可以在线程的顶层捕获System.Exception吗?

更新 该线程是一个长时间运行的线程,只应在应用程序停止时终止。因此,为了确保应用程序不会崩溃,我只需捕获System.Exception并记录错误。一切都重新创造。

        while (Terminate == false)
        {
            var discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());

            try
            {
                var criteria = new FindCriteria(typeof(T));
                criteria.Scopes.Add(new Uri(Scope));
                var discovered = discoveryClient.Find(criteria);
                discoveryClient.Close();
                discoveryClient = null;

                // do something with the endpoints
            }
            catch (OutOfMemoryException e)
            {
                m_Logger.LogException(e, "Exception when trying to discover clients (Contract: {0})", typeof(T).Name);
                throw;
            }
            catch (Exception e)
            {
                m_Logger.LogException(e, "Exception when trying to discover clients (Contract: {0})", typeof(T).Name);

                if (discoveryClient != null)
                    (discoveryClient as IDisposable).Dispose();
            }

        }

5 个答案:

答案 0 :(得分:3)

这取决于线程正在做什么以及应用程序中线程的上下文。一般来说,你应该遵循黄金法则:除非你知道如何处理它,否则不会发现异常。 (我当然正在简化,但这是一个经验法则。)

由于我们讨论的是System.Exception而不是某些子类,我假设您实际上并不知道如何处理异常。记录错误并让应用程序终止(捕获无法处理的异常的唯一合理理由)can be done而不从引发它的线程中捕获异常,所以简短的答案是否,没关系

如果我没记错的话,.NET 1实际上已经捕获并吞噬了后台线程上引发的所有异常。这导致了编写错误的程序中的许多问题,MS改变了.NET 2中的行为,让异常使应用程序崩溃 - 你可以想象他们非常有充分的理由做出如此突破性的改变

关于BackgroundWorker的更新:

请不要将BackgroundWorker的使用模式误认为“吞咽System.Exception正常”。以下是BackgroundWorker.RunWorkerCompleted的文档所说的内容:

  

您的RunWorkerCompleted事件处理程序   应该经常检查   AsyncCompletedEventArgs.Error和   AsyncCompletedEventArgs.Cancelled   访问之前的属性   RunWorkerCompletedEventArgs.Result   属性。如果引发异常   或者如果操作被取消,   访问   RunWorkerCompletedEventArgs.Result   财产引起了例外。

选择忽略这个建议或忽略故意返回值(否则仍然会抛出异常!)简单地说是糟糕的编程习惯。

答案 1 :(得分:2)

是的 - 这是一个很好的主意:)

嗯,我不明白为什么人们建议抓住顶级例外不是一个好主意。说真的,你没有抓住它们?

从实际的日常开发角度来看,如果您的后台线程有顶级异常,那么您希望了解它。您不希望应用程序崩溃,默认行为 - 用户不喜欢这样,令人惊讶。这是您绝对想要捕获异常和记录/恢复的少数几个地方之一。

答案 2 :(得分:0)

官方说这不是好习惯,但有时它已经完成了。

参数与在“主”线程上执行此操作完全相同。

一个主要问题是如果您吞下这样的错误,那么您的应用程序可能会非常错误地运行 - 例如它可能会覆盖关键的用户数据 - 而不是终止。


如果您确实选择了这条路线,您可能需要小心将ThreadAbortException排除在捕获之外 - 如果有人中止工作线程(这可能是也可能不是),这是一个“预期的异常”在您的应用程序中的情况)

答案 3 :(得分:0)

只处理你可以做的事情。为了不显示黄色屏幕,我个人更喜欢在global.asax事件中捕获unhandeld excetpion Application_error

答案 4 :(得分:-2)

我们通常不打算直接创建新主题。只有在少数情况下才可以接受。

因此,如果你确实在UI中使用new Thread(),那就不赞成了。

鼓励使用BackgroundWorkerTask<T>封装线程异常处理,因此不需要在catch块方面处理异常。


这4种情况是您需要自己的线程(来自CLR via C#):

的可接受情况
  

我强烈建议您使用   线程池执行异步   计算绑定操作   可能。但是,有一些   你可能想要的场合   显式创建一个专用的线程   执行特定的   计算绑定操作。通常情况下,   你想要创建一个专门的   线程,如果你要执行代码   这需要线程在一个   特殊状态不正常   用于线程池线程。例如,   如果我,我会创建一个专用线程   希望线程在特殊情况下运行   优先级(所有线程池线程都运行   在正常的优先级,你不应该   改变一个线程池线程   优先)。我也会考虑   如果我,创建和使用我自己的线程   想让线程成为前景   线程(所有线程池线程都是   因此,背景线程)   防止应用程序死亡   直到我的线程完成了它   任务。我也使用专用线程   如果计算绑定任务是   极长的跑步;这样,我   不会对线程池征税   它试图找出逻辑   是否要创建一个额外的   线。最后,我会使用专用的   线程,如果我想启动一个线程   并可能过早地中止它   调用Thread的Abort方法   (在第21章“CLR托管”中讨论过   和AppDomains“)。