转载自:http://www.cnblogs.com/levin9/articles/2319251.html

一:ThreadException和unhandledException的区别

  处理未捕获的异常是每个应用程序起码有的功能,C#在AppDomain提供了UnhandledException 事件来接收未捕获到的异常的通知。常见的应用如下:

static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
} static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception error = (Exception)e.ExceptionObject;
Console.WriteLine("MyHandler caught : " + error.Message);
}

未捕获的异常,通常就是运行时期的BUG,于是我们可以在UnhandledException 的注册事件方法CurrentDomain_UnhandledException中将未捕获异常的信息记录在日志中。值得注意的是,UnhandledException提供的机制并不能阻止应用程序终止,也就是说,CurrentDomain_UnhandledException方法执行后,应用程序就会被终止。

上面我们举的例子来自于控制台程序,UnhandledException可以在任何应用程序域中使用,在某些应用程序模型,如windows窗体程序,还存在ThreadException来处理 Windows 窗体线程中所发生的其未经处理的异常。即,在windows窗体程序中,使用 ThreadException 事件来处理 UI 线程异常,使用 UnhandledException 事件来处理非 UI 线程异常。ThreadException可以阻止应用程序终止。具体使用方法如下:

[STAThread]
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(UIThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new ErrorHandlerForm());
}
private static void UIThreadException(object sender, ThreadExceptionEventArgs t)
{
try
{
string errorMsg = "Windows窗体线程异常 : \n\n";
MessageBox.Show(errorMsg + t.Exception.Message + Environment.NewLine + t.Exception.StackTrace);
}
catch
{
MessageBox.Show("不可恢复的Windows窗体异常,应用程序将退出!");
}
} private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
Exception ex = (Exception)e.ExceptionObject;
string errorMsg = "非窗体线程异常 : \n\n";
MessageBox.Show(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
}
catch
{
MessageBox.Show("不可恢复的非Windows窗体线程异常,应用程序将退出!");
}
}

除了Windows窗体程序,再来说一下WPF程序。WPF的UI线程和Windows的UI线程有点不一样。WPF的UI线程是交给一个叫做调度器的类:Dispatcher。代码如下:

public App()
{
this.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
Exception ex = e.ExceptionObject as Exception;
string errorMsg = "非WPF窗体线程异常 : \n\n";
MessageBox.Show(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
}
catch
{
MessageBox.Show("不可恢复的WPF窗体线程异常,应用程序将退出!");
}
} private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
try
{
Exception ex = e.Exception;
string errorMsg = "WPF窗体线程异常 : \n\n";
MessageBox.Show(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
}
catch
{
MessageBox.Show("不可恢复的WPF窗体线程异常,应用程序将退出!");
}
}

无论是Windows窗体程序还是WPF程序,我们都看到捕获的异常当中分为"窗体线程异常"和"非窗体线程异常"。如在Windows窗体程序中,如果在窗体线程中,throw new Exception("窗体线程异常");将会触发ThreadException事件。

Thread t = new Thread((ThreadStart)delegate
{
  throw new Exception("非窗体线程异常");
});
t.Start(); //将会触发UnhandledException事件,然后整个应用程序会被终止。

二:多线程异常处理

多线程的异常处理,要采用特殊的做法。以下的处理方式会存在问题:

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

应用程序并不会在这里捕获线程t中的异常,而是会直接退出。从.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();

WPF窗体程序的处理方式与Windows窗体程序比较,有两个很有意思的地方:
  第一个是,在Windows窗体中,我们采用的是BeginInvoke方法。你会发现使用Invoke方法,并不能引发主线程的Application.ThreadException。而在WPF窗体程序中,无论是调度器的Invoke还是BeginInvoke方法都能将异常传递给主线程。
  第二个地方就是InnerException。WPF的工作线程异常将会抛到主线程,变成主线程异常的InnerException,而Windows窗体程序的工作线程异常,将会被吃掉,直接变为null,只是在异常的Message信息中保存工作线程异常的Message。

三:ASP.NET异常处理

  我们都知道ASP.NET的全局异常处理方法是Global中的Application_Error方法。我曾经查过ASP.NET的Appdomain.CurrentDomain.unhandledException,结果用反射得到的结果,unhandledException所注册的事件方法根本不是这个方法。联想到ASP.NET页面,包括这个全局处理类,都是交给aspnet_isapi.dll处理的,而aspnet_isapi.dll不是一个托管程序集。所以,应该理解为,ASP.NET的未捕获异常的处理,不同于托管异常(即CLR异常),而是交给aspnet_isapi.dll这个非托管DLL处理的。

转:异常处理之ThreadException、unhandledException及多线程异常处理的更多相关文章

  1. Winform异常处理之ThreadException、unhandledException及多线程异常处理

    异常处理之ThreadException.unhandledException及多线程异常处理 一:ThreadException和unhandledException的区别 处理未捕获的异常是每个应 ...

  2. 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)

    在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...

  3. 未找到数据,异常处理:exception when no_data_found then 异常处理语句;

    未找到数据. 在 select 字段 Into 变量 from 表 where 条件: 这种语句中很有可能会有select 不到数据的问题,导致报错"未找到数据" 要解决这种问题需 ...

  4. 异常处理第三讲,SEH(结构化异常处理),异常展开问题

    异常处理第三讲,SEH(结构化异常处理),异常展开问题 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 不知道昨天有木有 ...

  5. Java多线程异常处理

    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉.这一点是通过java.lang.Run ...

  6. 【异常处理】Java异常如何做异常处理

    类似SpringMVC项目的异常处理可以这样做: 整个项目创建全局的: 1.一个自定义异常如OneException和错误码,统一封装所有异常. 2.一个返回实体类ResponseEntity,包含返 ...

  7. 阶段3 3.SpringMVC·_06.异常处理及拦截器_3 SpringMVC异常处理之异常处理代码编写

    分三步 新建exception的包.然后添加SysException类 一般写异常都继承.Exception 定义Messgae属性,生成get和set 生成带参数的构造方法 选中异常的代码 Ctrl ...

  8. 阶段3 3.SpringMVC·_06.异常处理及拦截器_2 SpringMVC异常处理之演示程序异常

    原来的index.jsp删除.新建一个 创建pages文件夹.再创建success.jsp页面 重新部署项目 把这个项目移除掉 加入新的项目 启动tomcat服务器 模拟异常 方法抛出异常给前端控制器 ...

  9. 阶段3 3.SpringMVC·_06.异常处理及拦截器_1 SpringMVC异常处理之分析和搭建环境

    异常一级一级的抛出 前端控制器,调用异常处理器组件 搭建环境 注意下面两个的结尾的名称要个 Module Name对应起来. 导入开发的坐标 复制upload这个项目里面的 编程和生成 改成1.8 配 ...

随机推荐

  1. LeetCode-300.Longst Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...

  2. SSIS--(1)

    目标:两组数据比对,A 来源Excel ,B 来源 Sql server DB ,比对合并,取值放入目标 C 中 首先使用工具SSIS包 一,以数据源 A 为准核对B 中是否有A 的数据和计算等动作 ...

  3. IDEA与Elicpse

    IDEA的项目 = Elicpse的工作区 Elicpse的项目 = IDEA的模块 修改信息提示 Alt+/ 关闭当前窗口 Ctrl+W

  4. java -jstack

    一.介绍 jstack是java虚拟机自带的一种堆栈跟踪工具.jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项&qu ...

  5. IPFS私链搭建及常用操作命令

    1. 共享密钥 同一个IPFS私链内的所有节点必须共享同一个密钥才能加入. 首先我们使用密钥创建工具,创建一个密钥. 下载地址:https://github.com/Kubuxu/go-ipfs-sw ...

  6. 拖拽控件java版

    Button vv = new Button("vvvv");  DragSource.getDefaultDragSource().createDefaultDragGestur ...

  7. [Java in NetBeans] Lesson 07. JavaDoc and Unit Tests

    这个课程的参考视频和图片来自youtube. 主要学到的知识点有: 1. organize code into packages Create a package if want to make th ...

  8. 解放你生产力的10款效率工具,赶紧mark起来

    聪明的人总是善用工具 社会的快度发展赋予我们的一个幸运之处在于:你可以通过读书或使用工具去改善自身的处境甚至是阶层. 在父母那个时代,通过熟练使用办公软件,可以使一个在水泥地做帮工的青年走进格子间.而 ...

  9. vue的图片路径,和背景图片路径打包后错误解决

    最近在研究vue,老实的按照官网提供的,搭建的了 webpack+vue+vuex+vue-router,,因为是自己搭建的,所以踩了不少坑,一般问题百度都有,这个背景图片的问题,查了很久才解决. 1 ...

  10. 启动及更改tomcat 配置

    到tomcat安装的bin目录下面,双击那个startup.bat文件,启动Tomcat 去浏览器输入 http://localhost:8080/  然后出现下面的界面,那就说明你的tomcat配置 ...