编写高质量代码改善C#程序的157个建议——建议66:正确捕获多线程中的异常

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编写高质量代码改善C#程序的157个建议——建议66:正确捕获多线程中的异常相关的知识,希望对你有一定的参考价值。

 

建议66:正确捕获多线程中的异常

多线程的异常处理需要采用特殊的方式。一下这种方式会存在问题:

            try
            {
                Thread t = new Thread((ThreadStart)delegate
                {
                    throw new Exception("多线程异常");
                });
                t.Start();
            }
            catch (Exception error)
            {
                MessageBox.Show(error.Message + Environment.NewLine + error.StackTrace);
            }

应用程序并不会在这里捕获线程的异常,而是会直接退出。从.NET2.0开始,任何线程上未处理的异常都会导致应用程序的退出(先会触发APPDomain的UnhandledException)。上面的代码中的try-catch实际上捕获的还是当前线程的异常,而t属于新的异常,所以,正确的做法是:

            Thread t = new Thread((ThreadStart)delegate
            {
                try
                {
                    throw new Exception("多线程异常");
                }
                catch (Exception error)
                {
                    MessageBox.Show("工作线程异常:" + error.Message + Environment.NewLine + error.StackTrace);
                }
            });
            t.Start();

也就是说,新起的线程中异常的捕获,可以将线程内部代码全部try起来。原则上说,每个线程的业务异常应该在自己的内部处理完毕,不过,我们仍然需要一个办法,将线程内部的异常传递到主线程上。

在Windows窗体程序中,可以使用窗体的BeginInvoke方法将异常传递给主窗体线程:

            Thread t = new Thread((ThreadStart)delegate
            {
                try
                {
                    throw new Exception("非窗体线程异常");
                }
                catch (Exception ex)
                {
                    this.BeginInvoke((Action)delegate
                    {
                        throw ex;
                    });
                }
            });
            t.Start();

以上代码会最终引发主线程的Application.ThreadException。

在WPF窗体中,可以这样做:

            Thread t = new Thread((ThreadStart)delegate
            {
                try
                {
                    throw new Exception("非窗体线程异常");
                }
                catch (Exception ex)
                {
                    this.Dispatcher.Invoke((Action)delegate
                    {
                        throw ex;
                    });
                }
            });
            t.Start();

 

不过,除了上面的两种方式,我们更建议使用事件回调的方式将工作线程的异常包装到主线程。用事件回调的方式处理异常的好处是提供了统一的入口进行异常处理。这种方式将在建议85阐述。

 

 

 

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

以上是关于编写高质量代码改善C#程序的157个建议——建议66:正确捕获多线程中的异常的主要内容,如果未能解决你的问题,请参考以下文章

编写高质量代码改善C#程序的157个建议——建议28:理解延迟求值和主动求值之间的区别

编写高质量代码改善C#程序的157个建议——建议141:不知道该不该用大括号时,就用

编写高质量代码改善C#程序的157个建议——建议52:及时释放资源

编写高质量代码改善C#程序的157个建议——建议41:实现标准的事件模型

编写高质量代码改善C#程序的157个建议——建议111:避免双向耦合

编写高质量代码改善C#程序的157个建议——建议65:总是处理未捕获的异常