[C#.NET] 使用 try/catch 攔截例外應該注意事項

  • 52921
  • 0
  • 2013-07-05

[C#.NET] 使用 try/catch 攔截例外應該注意事項

在上篇寫道 [.NET] 使用 using 或 try/finally 清理資源,養成使用try/finally或是using習慣來釋放資源才能確保動作正常,在主執行緒(UI)程式碼裡可能會用以下片斷程式碼

public static void ToXml(string FileName, object Object)
{
    XmlSerializer xml = null;
    Stream stream = null;
    StreamWriter writer = null;
    try
    {
        xml = new XmlSerializer(Object.GetType());
        stream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Read);
        writer = new StreamWriter(stream, Encoding.UTF8);
        xml.Serialize(writer, Object);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        writer.Close();
        stream.Close();
    }
}

但上述的寫法很習慣的用catch來補捉例外,但有很多不好的習慣,為什麼!?

1.因為不同的類別有不同的例外行為 XmlSerializer 有它自己的例外,FileStream 也是,我們應該為各個類別建立明確的例外。

2.所以把Exception當成是首要的攔截是不對的,應該攔截較明確的例外狀況,所以要把Exception以及SystemException的捕捉擺在最後面。請勿攔截一般例外狀況型別因為攔截一般例外狀況類型會向程式庫使用者隱藏執行階段的問題,因而使偵錯變得更複雜。

3.Exception 是基底類別,其他的例外子類別都繼承於它們,子類別的訊息可能是父類別沒有的,所以用它們來捕捉例外,你可能會丟失很多東西。


分享一下我的做法,我一開始時(系統上線前)並不會寫catch區段的程式碼,當測試時發現了例外,如下圖:

image

 

我再為它捕上新的例外,當例外再度發生時,就會跑到該區塊

image

 

用 Exception 當下也可以捕捉到例外,這時再更改正確的例外。

image

 


剛剛那個方法是在MSDN上我在System.Xml.Serialization命名空間裡找不到相關的Exception類別,所以才出此下策,若在MSDN有相關的類別就比較容易處理。

再看看Stream類別的處理方式,Stream屬於System.IO命名空間,所以可以從這裡下手,我都是搜尋關鍵鍵字Exception,找到你認為可能發生的,就把它寫在catch區段,但並不是所有的例外都會寫出來,這時又得使用下策。

image

 

下圖就是發生FileNotFoundException例外

image

 

 

 


後記:

我在寫底層元件的時候,不寫任何的例外狀況,並確保資源有正確的被釋放,如下範例。例外全交由主執行緒也就是UI去處理,由它去捕捉例外並且統一記錄。

public static void ToXml(string FileName, object Object)
{
    XmlSerializer xml = null;
    Stream stream = null;
    StreamWriter writer = null;
    try
    {
        xml = new XmlSerializer(Object.GetType());
        stream = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Read);
        writer = new StreamWriter(stream, Encoding.UTF8);
        xml.Serialize(writer, Object);
    }
    finally
    {
        if (writer != null)
            writer.Close();

        if (stream != null)
            stream.Close();
    }
}

有人會說這樣寫例外發生時不就消失了!?其實並不會消失,只要你沒寫catch區段,它會一輩子跟著你;假設我在用戶端程呼叫時,當例外發生時,會先執行ToXml方法的finally區段,然後才會執行用戶端的catch區段

image

image

 

 

 

 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo