C#自定義異常處理及寫入日志
我們要站在異常一定可能會發(fā)生的角度來編寫C#自定義異常處理程序,應(yīng)對程序有可能發(fā)生的錯誤建立一個良好的C#自定義異常處理策略。
在做C#自定義異常處理的時候,最好能在應(yīng)用程序所有的入口處(事件處理函數(shù),主函數(shù),線程入口)使用try-catch。但是不要在程序構(gòu)造函數(shù)入口處添加try-catch,因為此處產(chǎn)生異常,它自己并沒有能力來處理,因為它還沒有構(gòu)造完畢,只能再向外層拋出異常。
但我們也不能盲目使用異常。而且使用異常,可能會在一定程度上影響到程序的性能(C#中使用異常一般不影響性能)。
- //自定義異常類
- publicclassMyException:ApplicationException
- {
- publicMyException(stringmessage):base(message)
- {
- }
- publicMyException(stringmessage,ExceptioninnerException)
- :base(message,innerException)
- {
- }
- }
全局異常處理、多線程中的異常處理
將全局異常處理函數(shù)的委托加入到Application.ThreadException中,實現(xiàn)全局異常處理,但它只能處理主線程中未捕獲的異常。在多線程異常處理時,工作線程/輔線程中產(chǎn)生異常,可以把它轉(zhuǎn)給主線程來完成異常處理。如果線程之間不通知,是無法直接捕捉異常的。若沒有去處理工作線程/輔線程中產(chǎn)生的異常,該異常將會“消失”掉。
為什么要把異常處理都交給主線程去做呢?舉個例子:在WinForm里我們使用多線程來處理界面元素,一旦有異常發(fā)生就將異常消息顯示出來。那么,是直接在異常發(fā)生后就MessageBox,還是將消息交給MainUI來統(tǒng)一顯示?試想一下,程序要是復(fù)雜點或是有多個界面采用多線程來顯示界面元素,那么采用前者,我們就算知道了異常的詳細(xì)信息,但可能還是很難找到究竟是哪里出了問題。而通過MainUI來顯示,情況就要好很多了,尤其是還設(shè)計到其他東西的時候(如:多語言環(huán)境)。當(dāng)然,這個例子只是很小的一個方面。下面就來看怎么來實現(xiàn):
- usingSystem;
- usingSystem.Drawing;
- usingSystem.Collections;
- usingSystem.ComponentModel;
- usingSystem.Windows.Forms;
- usingSystem.Data;
- usingSystem.Threading;
- namespaceThreadApp
- {
- publicclassfrmMain:System.Windows.Forms.Form
- {
- privateSystem.Windows.Forms.ButtonbtRun;
- /**////
- ///必需的設(shè)計器變量。
- ///
- privateSystem.ComponentModel.Containercomponents=null;
- publicdelegatevoidWorkerThreadExceptionHandlerDelegate(Exceptione);
- voidWorkerThreadExceptionHandler(Exceptione)
- {
- this.Text="Disposed.";
- MainUIThreadExceptionHandler(this,newSystem.Threading.ThreadExceptionEventArgs(e));
- }
- publicfrmMain()
- {
- InitializeComponent();
- }
- /**////
- ///清理所有正在使用的資源。
- ///
- protectedoverridevoidDispose(booldisposing)
- {
- if(disposing)
- {
- if(components!=null)
- {
- components.Dispose();
- }
- }
- base.Dispose(disposing);
- }
- Windows窗體設(shè)計器生成的代碼#regionWindows窗體設(shè)計器生成的代碼
- /**////
- ///設(shè)計器支持所需的方法-不要使用代碼編輯器修改
- ///此方法的內(nèi)容。
- ///
- privatevoidInitializeComponent()
- {
- this.btRun=newSystem.Windows.Forms.Button();
- this.SuspendLayout();
- //
- //btRun
- //
- this.btRun.Location=newSystem.Drawing.Point(72,24);
- this.btRun.Name="btRun";
- this.btRun.TabIndex=0;
- this.btRun.Text="Run";
- this.btRun.Click+=newSystem.EventHandler(this.btRun_Click);
- //
- //frmMain
- //
- this.AutoScaleBaseSize=newSystem.Drawing.Size(6,14);
- this.ClientSize=newSystem.Drawing.Size(224,69);
- this.Controls.Add(this.btRun);
- this.Name="frmMain";
- this.Text="ThreadApp";
- this.ResumeLayout(false);
- }
- #endregion
- /**////
- ///應(yīng)用程序的主入口點。
- ///
- [STAThread]
- staticvoidMain()
- {
- Application.ThreadException+=newThreadExceptionEventHandler(MainUIThreadExceptionHandler);
- Application.Run(newfrmMain());
- }
- publicstaticvoidMainUIThreadExceptionHandler(Exceptione)
- {
- MainUIThreadExceptionHandler(null,newSystem.Threading.ThreadExceptionEventArgs(e));
- }
- publicstaticvoidMainUIThreadExceptionHandler(objectsender,ThreadExceptionEventArgst)
- {
- MessageBox.Show(t.Exception.Message,"Exception",
- MessageBoxButtons.OK,
- MessageBoxIcon.Warning);
- }
- privatevoidThrowException()
- {
- thrownewNotImplementedException();
- }
- privatevoidRun()
- {
- try
- {
- this.Text="Waiting";//[錯誤]這里在2.0里是編譯不通過的。因為它已經(jīng)違背了我們的原則——不要跨線程操作(當(dāng)前線程對界面線程的元素進(jìn)行了操所)
- Thread.Sleep(2000);
- this.Text="ThrowException";
- ThrowException();
- this.Text="Finished";//[錯誤](同上)
- }
- catch(Exceptione)
- {
- //如果涉及到多線程的互操作時,
- //可以運用BeginInvoke方法來實現(xiàn)多線程間的互訪問。
- this.BeginInvoke(
- newWorkerThreadExceptionHandlerDelegate(
- WorkerThreadExceptionHandler),
- newobject[]{e});}
- }
- privatevoidbtRun_Click(objectsender,System.EventArgse)
- {
- ThreadStartts=newThreadStart(Run);
- Threadt=newThread(ts);
- t.Start();
- //thrownewNotSupportedException();
- }
- }
- }
【編輯推薦】