利用委托机制处理
.NET
中的异常
<?xml:namespace prefix = o ns = “urn:schemas-microsoft-com:office:office” />
Terrylee
,
2005
年
12
月
10
日
概述
在
.NET
中,可以轻松的通过
try-catch
块来捕获异常。为了防止在应用程序中出现未处理的异常,可以通过添加一个全局的异常处理函数,如果是多线程的处理,还必须考虑除了主线程之外的工作线程中的异常处理办法,这里用委托机制来实现。
主线程的异常处理
使用
Application
对象中的
ThreadException
属性设置一个
delegate
来捕获所有的未处理的主线程中出现的异常。注意这个全局异常处理程序,只能捕获到主线程中的异常,对于我们自己添加的工作线程、辅助线程的异常是捕获不到的。
在应用程序入口添加全局异常处理:
1
/**/
///
<summary>
2
///
应用程序的主入口点。
3
///
</summary>
4
[STAThread]
5
static
void
Main()
6
{
7
/**/
///
添加主线程的全局异常处理
8
Application.ThreadException
+=
new
9
ThreadExceptionEventHandler(
10
MainUIThreadExceptionHandler);
11
12
Application.Run(
new
Form1());
13
}
处理程序:
1
public
static
void
MainUIThreadExceptionHandler(Exception ex)
2
{
3
MainUIThreadExceptionHandler(
null
,
new
4
ThreadExceptionEventArgs(ex));
5
}
6
7
/**/
///
<summary>
8
///
主线程全局异常信息的处理
9
///
</summary>
10
///
<param name=”sender”></param>
11
///
<param name=”t”></param>
12
public
static
void
MainUIThreadExceptionHandler(
object
13
sender, ThreadExceptionEventArgs e)
14
{
15
MessageBox.Show(
16
”
应用程序发生了如下的异常信息
”
17
+
”
:
”
+
(
char
)
13
18
+
(
char
)
13
+
e.Exception.Message
19
+
(
char
)
13
+
(
char
)
13
20
+
”
请于系统管理员取得联系!
”
21
+
(
char
)
13
+
(
char
)
13
22
,
”
异常信息
”
23
, MessageBoxButtons.OK
24
, MessageBoxIcon.Error
25
, MessageBoxDefaultButton.Button1
26
, MessageBoxOptions.ServiceNotification);
27
}
工作线程的异常处理
编写多线程代码时,我们必须考虑在工作线程中出现的异常。在线程的入口使用
try-catch
块,并通过
delegate
将发生的异常通知给主线程。必须将异常信息通知主线程,否则应用程序不会报错,异常将会消失。
在线程入口使用
try-catch
块:
1
/**/
///
<summary>
2
///
在线程的入口点加入try-catch块
3
///
</summary>
4
private
void
DataSave()
5
{
6
try
7
{
8
CreateException();
9
}
10
catch
(Exception e)
11
{
12
/**/
///
通过delegate转向工作线程的异常处理
13
new
WorkerThreadExceptionHandlerDelegate(
14
WorkerThreadExceptionHandler).BeginInvoke(e
15
,
null
16
,
null
);
17
}
18
}
工作线程异常的处理:
1
/**/
///
<summary>
2
///
声明工作线程的delegate
3
///
</summary>
4
public
delegate
void
5
WorkerThreadExceptionHandlerDelegate(Exception e);
6
7
/**/
///
<summary>
8
///
工作线程的异常处理
9
///
</summary>
10
///
<param name=”e”></param>
11
public
void
WorkerThreadExceptionHandler(Exception e)
12
{
13
/**/
///
添加其他的处理代码
14
15
///
通知全局异常处理程序
16
MainUIThreadExceptionHandler(
17
this
,
new
System.Threading.
18
ThreadExceptionEventArgs(e));
19
}
总结
对于捕获到异常,我们可以
Log
到文件或者数据库,但是必须保证捕获到所有的异常,以上通过委托机制实现了
.NET
中的主线程以及工作线程中的异常捕获。
完整的程序代码:
1
using
System;
2
using
System.Drawing;
3
using
System.Collections;
4
using
System.ComponentModel;
5
using
System.Windows.Forms;
6
using
System.Data;
7
using
System.Threading;
8
9
namespace
UseDelegateException
10
{
11
/**/
///
<summary>
12
///
功能:利用Delegate实现异常的全局处理
13
///
编写:Terrylee
14
///
日期:2005年12月10日
15
///
</summary>
16
public
class
Form1 : System.Windows.Forms.Form
17
{
18
private
System.Windows.Forms.Button btnMainUIThread;
19
private
System.Windows.Forms.Button btnWorkThread;
20
/**/
///
<summary>
21
///
必需的设计器变量。
22
///
</summary>
23
private
System.ComponentModel.Container components
=
null
;
24
25
public
Form1()
26
{
27
//
28
//
Windows 窗体设计器支持所必需的
29
//
30
InitializeComponent();
31
32
//
33
//
TODO: 在 InitializeComponent 调用后添加任何构造函数代码
34
//
35
}
36
37
/**/
///
<summary>
38
///
清理所有正在使用的资源。
39
///
</summary>
40
protected
override
void
Dispose(
bool
disposing )
41
{
42
if
( disposing )
43
{
44
if
(components
!=
null
)
45
{
46
components.Dispose();
47
}
48
}
49
base
.Dispose( disposing );
50
}
51
52
Windows 窗体设计器生成的代码
#region
Windows 窗体设计器生成的代码
53
/**/
///
<summary>
54
///
设计器支持所需的方法 – 不要使用代码编辑器修改
55
///
此方法的内容。
56
///
</summary>
57
private
void
InitializeComponent()
58
{
59
this
.btnMainUIThread
=
new
System.Windows.Forms.Button();
60
this
.btnWorkThread
=
new
System.Windows.Forms.Button();
61
this
.SuspendLayout();
62
//
63
//
btnMainUIThread
64
//
65
this
.btnMainUIThread.Location
=
new
System.Drawing.Point(
40
,
72
);
66
this
.btnMainUIThread.Name
=
”
btnMainUIThread
”
;
67
this
.btnMainUIThread.Size
=
new
System.Drawing.Size(
112
,
48
);
68
this
.btnMainUIThread.TabIndex
=
0
;
69
this
.btnMainUIThread.Text
=
”
主线程异常
”
;
70
this
.btnMainUIThread.Click
+=
new
System.EventHandler(
this
.btnMainUIThread_Click);
71
//
72
//
btnWorkThread
73
//
74
this
.btnWorkThread.Location
=
new
System.Drawing.Point(
240
,
72
);
75
this
.btnWorkThread.Name
=
”
btnWorkThread
”
;
76
this
.btnWorkThread.Size
=
new
System.Drawing.Size(
112
,
48
);
77
this
.btnWorkThread.TabIndex
=
1
;
78
this
.btnWorkThread.Text
=
”
工作线程异常
”
;
79
this
.btnWorkThread.Click
+=
new
System.EventHandler(
this
.btnWorkThread_Click);
80
//
81
//
Form1
82
//
83
this
.AutoScaleBaseSize
=
new
System.Drawing.Size(
6
,
14
);
84
this
.ClientSize
=
new
System.Drawing.Size(
392
,
197
);
85
this
.Controls.Add(
this
.btnWorkThread);
86
this
.Controls.Add(
this
.btnMainUIThread);
87
this
.MaximizeBox
=
false
;
88
this
.Name
=
”
Form1
”
;
89
this
.Text
=
”
Form1
”
;
90
this
.ResumeLayout(
false
);
91
92
}
93
#endregion
94
95
/**/
///
<summary>
96
///
应用程序的主入口点。
97
///
</summary>
98
[STAThread]
99
static
void
Main()
100
{
101
/**/
///
添加主线程的全局异常处理
102
Application.ThreadException
+=
new
103
ThreadExceptionEventHandler(
104
MainUIThreadExceptionHandler);
105
106
Application.Run(
new
Form1());
107
}
108
109
public
static
void
MainUIThreadExceptionHandler(Exception ex)
110
{
111
MainUIThreadExceptionHandler(
null
,
new
112
ThreadExceptionEventArgs(ex));
113
}
114
115
/**/
///
<summary>
116
///
主线程全局异常信息的处理
117
///
</summary>
118
///
<param name=”sender”></param>
119
///
<param name=”t”></param>
120
public
static
void
MainUIThreadExceptionHandler(
object
121
sender, ThreadExceptionEventArgs e)
122
{
123
MessageBox.Show(
124
”
应用程序发生了如下的异常信息
”
125
+
”
:
”
+
(
char
)
13
126
+
(
char
)
13
+
e.Exception.Message
127
+
(
char
)
13
+
(
char
)
13
128
+
”
请于系统管理员取得联系!
”
129
+
(
char
)
13
+
(
char
)
13
130
,
”
异常信息
”
131
, MessageBoxButtons.OK
132
, MessageBoxIcon.Error
133
, MessageBoxDefaultButton.Button1
134
, MessageBoxOptions.ServiceNotification);
135
}
136
137
/**/
///
<summary>
138
///
声明工作线程的delegate
139
///
</summary>
140
public
delegate
void
141
WorkerThreadExceptionHandlerDelegate(Exception e);
142
143
/**/
///
<summary>
144
///
工作线程的异常处理
145
///
</summary>
146
///
<param name=”e”></param>
147
public
void
WorkerThreadExceptionHandler(Exception e)
148
{
149
/**/
///
添加其他的处理代码
150
151
///
通知全局异常处理程序
152
MainUIThreadExceptionHandler(
153
this
,
new
System.Threading.
154
ThreadExceptionEventArgs(e));
155
}
156
/**/
///
<summary>
157
///
制造异常信息,这里抛出一个除0的异常
158
///
</summary>
159
private
void
CreateException()
160
{
161
int
a
=
1
;
162
int
b
=
0
;
163
164
int
c;
165
c
=
a
/
b;
166
}
167
168
/**/
///
<summary>
169
///
在线程的入口点加入try-catch块
170
///
</summary>
171
private
void
DataSave()
172
{
173
try
174
{
175
CreateException();
176
}
177
catch
(Exception e)
178
{
179
/**/
///
通过delegate转向工作线程的异常处理
180
new
WorkerThreadExceptionHandlerDelegate(
181
WorkerThreadExceptionHandler).BeginInvoke(e
182
,
null
183
,
null
);
184
}
185
}
186
187
/**/
///
<summary>
188
///
发生主线程异常
189
///
</summary>
190
///
<param name=”sender”></param>
191
///
<param name=”e”></param>
192
private
void
btnMainUIThread_Click(
object
sender, System.EventArgs e)
193
{
194
/**/
///
这里出现一个异常,我们不予捕获,交由全局处理函数
195
CreateException();
196
}
197
198
/**/
///
<summary>
199
///
发生工作线程异常
200
///
</summary>
201
///
<param name=”sender”></param>
202
///
<param name=”e”></param>
203
private
void
btnWorkThread_Click(
object
sender, System.EventArgs e)
204
{
205
Thread t
=
new
Thread(
new
ThreadStart(DataSave));
206
t.Start();
207
}
208
}
209
}
210