课程名: Windows应用程序开发入门到精通七:优化 .NET异常处理
1. 多个 catch 块的情况时会过滤异常,先截获具体的异常,再截获一般的异常,并且这是从编译器的层次就支持的。
2.应该从系统异常 (System.ApplicationException) 派生自己的具体异常,从而为特定的应用程序提供更好的支持。
3.异常处理技术: 1 )记录异常:在文件中记录异常;在数据库中记录;在 Eventlog 中记录。 2 )发 email 等信息来通知异常。总之,要以用户友好的方式通知异常的发生。
4. 使用 Application 对象中的 ThreadException 属性来设置一个 delegate 来捕获所有未处理的主线程中出现的异常,但并不能处理你自己创建的工作进程中出现的异常。
public
static
void
Main(
string
[] args)
{ Application.ThreadException += new ThreadExceptionEventHandler( MainUIThreadExceptionHandler); Demo6(); System.Windows.Forms.Application.Run( new NorthwindMDIMain()); }
public
static
void
MainUIThreadExceptionHandler( Exception e)
{ MainUIThreadExceptionHandler( null , new System.Threading. ThreadExceptionEventArgs(e)); }
public
static
void
MainUIThreadExceptionHandler(
object
sender, ThreadExceptionEventArgs t)
{ ExceptionManager.Publish(t.Exception); // Tell the user a boo-boo occurred MessageBox.Show( " Northwind Orders has encountered the following " + " problem: " + ( char ) 13 + ( char ) 13 + t.Exception.Message + ( char ) 13 + ( char ) 13 + " Please contact your administrator or the " + " Northwind Help desk at " + ( char ) 13 + ( char ) 13 + " 1-855-555-5555. " + ( char ) 13 + ( char ) 13 + " We apologize for the inconvenience. " , " Northwind Orders Encountered a Problem " , MessageBoxButtons.OK , MessageBoxIcon.Error , MessageBoxDefaultButton.Button1 , MessageBoxOptions.ServiceNotification); }
5 ,必须考虑在工作线程中出现的异常,在线程的入口使用 try-catch, 并且使用 delegate 等方式将异常通知给主线程,此外,线程之间要访问对方的界面成员时,应该通过 BeginInvoke ()方法来进行。
public
delegate
void
DoneDelegate(
bool
Stopped);
public
delegate
void
WorkerThreadExceptionHandlerDelegate(Exception e);
void
WorkerThreadExceptionHandler(Exception e)
{ UpdateProgress(); SetStatusText( " Problem Encountered " ); this .Text = " Customers " ; btnSave.Text = " Save " ; btnClose.Enabled = true ; // Call the global exception handler MainClass.MainUIThreadExceptionHandler( this , new System.Threading. ThreadExceptionEventArgs(e)); }
private
void
btnSave_Click(
object
sender, System.EventArgs e)
{ try { if ( true == btnSave.Enabled) { this .Text = " Customers (Saving ) " ; btnSave.Enabled = false ; btnClose.Enabled = false ; System.Threading.Thread t = new System.Threading.Thread( new System.Threading.ThreadStart( SaveCustomer)); t.Start(); } else { isCanceled = true ; btnSave.Enabled = true ; } } catch (NotSupportedException exception) { MessageBox.Show( " Code not done yet " + exception.Message ); } catch (Exception exception) { // Tell the user a boo-boo occurred MainClass.MainUIThreadExceptionHandler( this ,new System.Threading. ThreadExceptionEventArgs(exception)); MessageBox.Show( " Northwind Orders has encountered a problem. " + " Please contact your administrator or the " + " Northwind Help desk at " + ( char ) 13 + ( char ) 13 + " 1-855-555-5555. " + ( char ) 13 + ( char ) 13 + " We apologize for the inconvenience. " , " Northwind Orders Encountered a Problem " , MessageBoxButtons.OK , MessageBoxIcon.Error); } finally { this .Cursor = Cursors.Default; } }
private
void
SaveCustomer()
{ try { SetStatusText( " Saving record on a background thread " ); // TODO: Add code to save the customer record this .BindingContext[dsCustomers, " Customers " ]. EndCurrentEdit(); dsCustomers objDataSetChanges = ((dsCustomers) (dsCustomers.GetChanges())); if ( null != objDataSetChanges) new NorthwindDataAccess().UpdateCustomers( objDataSetChanges); isCanceled = false ; DoneDelegate delDone = new DoneDelegate(Done); delDone.BeginInvoke(isCanceled, null , null ); } catch (Exception e) { new WorkerThreadExceptionHandlerDelegate( WorkerThreadExceptionHandler).BeginInvoke(e , null ,null ); } }
private
void
Done (
bool
Stopped)
{ UpdateProgress(); this .Text = " Customers " ; btnSave.Enabled = true ; btnClose.Enabled = true ; if (Stopped) { MessageBox.Show( " Save Stopped " , " Stopped " , MessageBoxButtons.OK , MessageBoxIcon.Warning); SetStatusText(" Save Stopped " ); } else { MessageBox.Show( " Save Done " , " Done " , MessageBoxButtons.OK , MessageBoxIcon.Information); SetStatusText( " Save Done " ); } }
6 ,在构造函数中不要加 try-catch ,因为这会把异常再抛给外部方法,还不如不处理,直接抛给外部好了。
7 ,异常处理程序块采用的是 publisher/subscriber 设计模式,在工程中添加对它的引用,并引入名称空间 Microsoft.ApplicationBlocks.ExceptionManagement 就可以使用 ExceptionManager.Publish() 来进行异常的发布。在 app.config 中可以对异常管理进行启 / 停,还可以添加自己的异常处理模块。
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
configSections
>
<
section
name
="exceptionManagement"
type
="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler,Microsoft.ApplicationBlocks.ExceptionManagement"
/>
</
configSections
>
<
exceptionManagement
mode
="on"
>
<
publisher
mode
="on"
assembly
="Microsoft.ApplicationBlocks.ExceptionManagement"
type
="Microsoft.ApplicationBlocks.ExceptionManagement.DefaultPublisher"
logname
="Northwind Exceptions Log"
applicationname
="Northwind Traders Orders"
/>
</
exceptionManagement
>
</
configuration
>
public
static
void
MainUIThreadExceptionHandler(
object
sender, ThreadExceptionEventArgs t)
{ ExceptionManager.Publish(t.Exception); // Tell the user a boo-boo occurred MessageBox.Show( " Northwind Orders has encountered the following " + " problem: " + ( char ) 13 + ( char ) 13 + t.Exception.Message + ( char ) 13 + ( char ) 13 + " Please contact your administrator or the " + " Northwind Help desk at " + ( char ) 13 + ( char ) 13 + " 1-855-555-5555. " + ( char ) 13 + ( char ) 13 + " We apologize for the inconvenience. " , " Northwind Orders Encountered a Problem " , MessageBoxButtons.OK , MessageBoxIcon.Error , MessageBoxDefaultButton.Button1 , MessageBoxOptions.ServiceNotification); }
可以在 “ 事件查看器 ” 中看到异常已经发布进来了: