簡體   English   中英

我是否應該在我的方法中捕獲“純文檔”目的的異常?

[英]Should I catch exceptions in my method for “purely documenting” purposes?

我應該在我的方法中捕獲“純文檔”目的的異常,從而將錯誤文檔封裝在方法本身中,還是調用者的責任?

假設我在我的EncryptPackage()方法中調用了許多其他方法,包括框架方法,這可能會引發許多異常。 using塊包裝所有東西,因此不需要捕獲清理異常(或者我使用try / finally進行清理)。 我是否應該捕獲異常,並提供有關該方法的上下文的詳細信息,還是調用方法的責任?

情況如下:

[Serializable]
class TestClassException : Exception
{
    public TestClassException() : base() { }
    public TestClassException(string message) : base(message) { }
    public TestClassException(string message, Exception innerException) : base(message, innerException) { }
}

class TestClass
{
    public TestClass() { }

    public void EncryptPackage()
    {
        try
        {
            DoSomething();
            DoAnotherThing();
        }
        catch (Exception ex)
        {
            throw new TestClassException("Error occurred during package encryption", ex);
        }
    }
}

class ConsumerExample
{
    public ConsumerExample() { }

    public void DoSomeStuff()
    {
        TestClass testClass = new TestClass();

        try
        {
            testClass.EncryptPackage();
        }
        catch (TestClassException ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
        }
    }
}

在此代碼中,請注意EncryptPackage()方法如何捕獲所有可能的異常,只是為了“修飾錯誤文本”,“包加密期間發生錯誤”文本。 EncryptPackage()在這里封裝了錯誤描述邏輯。

這是另一種技術:

class TestClass2
{
    public TestClass2() { }

    public void EncryptPackage()
    {
        DoSomething();
        DoAnotherThing();
    }
}

class ConsumerExample2
{
    public ConsumerExample2() { }

    public void DoSomeStuff()
    {
        TestClass testClass = new TestClass();

        try
        {
            testClass.EncryptPackage();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show("Error occurred during package encryption.\r\n\r\n" + ex.ToString());
        }
    }
}

在此示例中, EncryptPackage()不會捕獲任何內容,因為調用程序無論如何都會記錄錯誤情況,並且“在程序包加密期間發生錯誤。\\ r \\ n \\ r \\ n”消息。

請注意,這是一個非常簡化的示例,在現實世界中將有許多分層類,並且異常將通過長調用堆棧傳播,因此首選捕獲異常的方法是什么? 第二種方法似乎“更干凈”,因為異常是在一個層中處理的,其中一些“實際處理”(例如顯示給用戶)將要發生。 調用堆棧信息將保留在異常對象中,因此從技術上講,可以找出拋出異常的確切位置。 但是......這似乎並不像第一種方法那樣“記錄良好”,其中每個抽象級別都將自己的描述添加到錯誤中,從而在innerException成員中保留先前的異常。 在這種情況下,當執行離開TestClass層,它已經包含了這個類中發生的錯誤的詳細說明。 所以這感覺是錯誤處理邏輯的更好封裝。

哪一個使用?

在Effective Java中有一章關於這一點

較高層應該捕獲較低級別的異常,並且在它們的位置拋出可以用更高級別抽象來解釋的異常。 這個成語被稱為異常翻譯。

我更喜歡你的第二個例子,主要是因為它可以顯着減少你必須編寫的錯誤處理代碼的數量,特別是如果你正在編寫自定義異常 - 在第一個例子中你最終可能會得到許多自定義異常類好處(你已經有調用堆棧告訴你異常的來源)。

您可能認為有一個更具描述性的錯誤消息很好,但是誰從中受益? 最終用戶? 您是否應該向用戶顯示異常消息(以及您要使用的語言)? 很多時候用戶只需要知道存在內部錯誤,他們應該放棄(重啟),或者再試一次。 您對開發人員有益嗎? 您可能最終會使用前面的源代碼檢查調用堆棧,因此您不需要更具描述性的消息,您可以自己查看代碼在此處執行的操作。

這不是一個硬性規定。 大多數情況下,我只捕獲頂級異常,在那里我記錄它們並向用戶報告錯誤。 如果您直接向用戶報告異常,那么原始異常通常不會從轉換中受益,例如,如果您嘗試打開不存在的文件,那么System.IO.FileNotFoundException足夠描述,那么為什么要將它轉換為別的什么? 你真的想做同樣的判斷電話(“我比圖書館作者更了解所以我要翻譯他們精心設計的例外情況”),因為那里有所有的例外情況嗎? 如果我想從它們中恢復(通常不可能),我只捕獲較低的異常,或者,很少,我想將它們轉換為更具描述性的異常。

在分層體系結構中,在層之間轉換異常是有意義的,例如,將來自數據訪問層的異常捕獲到適合應用程序層的形式,以及類似於應用程序層和用戶界面之間的異常,但我不喜歡不知道你是否正在研究那種類型的系統。

如果要記錄異常,則應在xml文檔中使用該方法的異常標記 然后,這可以用於文檔中的常規幫助文件,例如,使用SandCastle

根據上面的@Sjoerd,轉換異常,使它們處於相同的抽象級別。 在您的情況下,EncryptPackage應該轉換任何較低級別的異常本身,而不是調用者。

假設較低級別的異常來自數據庫層(比如DBException)。 調用者是否希望了解DBException? 答案是否定的:調用者想要包含一個包,而不是DBException。 出於調試目的,應將較低級別的異常鏈接在較高級別的異常中。

最后,我知道TestClassException是一個例子,但要確保異常類清楚地描述了這個問題:我個人不喜歡平淡無奇的異常類(除了為其他異常創建一個公共基類)。

您應該嘗試/捕捉一些容易區分的情況:

  • 任何可以“外部”調用的方法,例如應用程序的入口點,UI事件,多線程調用等。 在每一個捕獲物上放置一些日志輸出或消息。 這將阻止您的應用程序崩潰(大部分),並為您或用戶提供有關如何解決問題的一些反饋。

  • 什么時候你可以真正處理異常。 這意味着您的應用可以選擇輔助數據庫或服務器URL,應用不同的處理等。

  • 當您想要阻止某些可選項破壞主工作流時,例如,未能刪除臨時文件不應導致您的進程失敗。

  • 可能還有其他一些你需要嘗試/捕獲的地方,但這些應該是罕見的

總是將錯誤處理與一個體面的日志記錄和/或消息傳遞方式結合起來,不要讓任何異常信息消失,因為這就是你獲取應用程序的方式而且“沒有明顯的理由”表現不好 - 至少原因應該是顯而易見的。

此外 - 不要使用例外來控制您的工作流程。 真的不應該有任何“拋出”,除非絕對沒有別的辦法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM