簡體   English   中英

使用try / catch / finally執行常規類?

[英]Using a general class for execution with try/catch/finally?

在我的代碼中,我發現自己有很多不同的方法:

try
{
  runABunchOfMethods();
}
catch (Exception ex)
{
  logger.Log(ex);
}

怎么樣創造這個:

public static class Executor
{

    private static ILogger logger;

    public delegate void ExecuteThis();

    static Executor()
    {
        // logger = ...GetLoggerFromIoC();
    }

    public static void Execute<T>(ExecuteThis executeThis)
        where T : Exception
    {
        try
        {
            executeThis();
        }
        catch (T ex)
        {
            // Some kind of Exception Handling Strategy...
            logger.Log(ex);
            // throw;
        }
    }

}

只是像這樣使用它:

private void RunSomething()
{
  Method1(someClassVar);
  Method2(someOtherClassVar);
}

...

Executor.Execute<ApplicationException>(RunSomething);

這種方法有什么缺點嗎? (您可以在需要finally時添加Executor方法和委托,並使用泛型來處理要捕獲的Exeception類型...)

編輯:很抱歉不清楚 - 我真正想到的是關於嘗試將代碼的執行從有問題的類移動到更廣泛的類來執行此操作的一般想法的一些輸入。 我只是快速模擬了一個解決方案,但在現實生活中,您自然會使用諸如異常處理策略,抽象執行基類以及針對特定層/系統部分的更專業的執行類。 我通常使用try ... / runABunchOfMethods-part創建一個方法(這會執行異常處理,具有特殊的異常),調用runABunchOfMethods,而runABunchOfMethods又執行一組有限的其他方法“clean code”樣式。

我會在某些層面上購買混淆論證,但如果整個解決方案/架構采用這種提議的方法,新的程序員應該能夠理解這種模式。

我編輯了Executor以包含一個通用T,允許調用代碼指定exeception以顯示如何處理專門的exeception。 在其他情況下,你可能會有很多問題:es取決於你想要做什么,但這些是我所討論的具體子類中的特殊情況。

縮減是您的一般異常處理方法。 如果沒有充分的理由,你不應該捕獲基類Exception 它可以隱藏各種問題; 好吧,你記錄它們,但你的代碼不知道它只是內存不足 ,或者文件不存在並繼續,好像根本沒有問題。
您在此處描述的方法將鼓勵一般的異常處理。

有關:
捕獲一般異常真的那么糟糕嗎?
捕獲System.Exception等非特定異常是不好的做法? 為什么?

編輯 (對OP的編輯和澄清的回應):
我不確定你想要達到什么目的。 Basicall你隱藏一個異常(一般或指定 - 它只是被吞下)。 調用你的方法Executor.Hide<ApplicationException>( RunSomething ); 很清楚這里發生了什么。 但吞咽異常有什么好處嗎? 我不這么認為。 同樣,有些地方你需要這個 - 但它們很少見,應該有意選擇。 您提供的方法鼓勵在不考慮的情況下吞下異常。
你注釋掉了重新拋出線( throw ex或者更好的只是throw ,它保留了堆棧)。 你啟用這條線怎么辦? 基本上只是記錄。 你捕獲一個異常,記錄它並重新拋出它...再次捕獲它? 你為什么不把你的伐木記錄到后一個地方?
當你能夠處理它時,嘗試僅捕獲異常。 那里你也可以登錄。 任何好的記錄器都能顯示堆棧跟蹤,這樣您就不會丟失任何信息。

有關:
在哪里放試試?

您獲得了另一層次的間接性,這可能會使您的代碼更難以閱讀和理解(特別是對於第一次查看您的代碼的人)。

缺點是缺乏靈活性。 如果要從正在調用的方法之一中的特定異常中恢復,例如在與SMTP服務器的連接失敗時,您可能希望將出站郵件的內容存儲在數據庫中以便稍后重試,該怎么辦? 這就是為什么你應該盡可能避免捕獲一般的Exception類型。

此外,您失去了一些代碼的清晰度(在我看來,無論如何),因為很難看到異常處理發生的位置。

如果你在很多課程中看到那些代碼,那么你在我的書中做了一些非常錯誤的事情:-) 至少你應該重新拋出異常(只用“throw”,而不是“throw(ex) “),但是記錄基本異常的整個想法只是為了記錄它(或者實際上在任何時候,禁止一些邊緣情況)對我來說不是正確的方法。

我不知道你正在編寫什么樣的應用程序,但是你不能掛鈎AppDomain.UnhandledException這樣的事件,它會在任何線程中出現未處理的異常(你沒有捕獲的異常)時觸發,然后記錄這些事件嗎? 如果您還想記錄可恢復的異常,您可能希望將其與更具體的catch語句相結合,這些語句也會記錄。

你沒有贏得任何東西,但是你失去了一些東西:

  • 可讀性
  • 簡單(你介紹另一個類,讀者必須理解的另一個代表)
  • 你不能簡單地跨過Executor.Execute來獲取Method1(...)。 如果您跳過,則跳過代理中的整個代碼塊。
  • ...

通常,在應用程序中記錄異常的最佳模式是捕獲代碼中頂級方法的異常。

  • 在控制台應用程序中,您應該捕獲並記錄Main異常。
  • 在WinForms應用程序中,您應該捕獲並記錄事件處理程序中的異常。
  • 在服務中,您應該捕獲並記錄異常,然后記錄工作線程的ThreadProcs
  • 等等。

在應用程序的幾乎所有其他點上,您應該只捕獲特定的異常,然后重新拋出包裝原始異常的新異常。 如果您不需要包裝原始異常,則首先不需要捕獲原始異常。

像這樣設置你的應用程序只會導致你捕獲,記錄和“吞下”異常的幾個地方。

如果要保持對象清潔,可以考慮使用像PostSharp這樣的AOP框架。 然后,如果您願意,可以在一個地方處理異常記錄(例如)。

編輯:

可以使用postsharp刪除try / catch塊 - 這是一個可以在PostSharp中創建的示例常見異常處理程序:

[Serializable]
public class CommonExceptionHandling : OnExceptionAspect
{
    public override void OnException(MethodExecutionEventArgs eventArgs)
    {
        // can do some logging here
        // ...

        // throw the exception (out of postsharp) to where it occurred:
        eventArgs.FlowBehavior = FlowBehavior.RethrowException;                       

        // If you want to ignore the exception, you can do this:
        //eventArgs.FlowBehavior = FlowBehavior.Return;

        base.OnException(eventArgs);
    }
}

如果將此屬性應用於類,則該類中拋出的任何方法的任何異常都將通過上述代碼進行定向。

我會跳到“它會讓你有可能濫用例外,只能抓住一般水平”的潮流。 但是,在更專業的情況下,您可能會從某種“異常處理委托包裝器”中受益。 例如,如果您在與DB相關的類中進行大量工作(始終拋出相同的異常),則可以使用專用的DB異常包裝器。

但最終,例外的“混亂”代碼是使代碼安全的缺點。

剛開始......

您不應該在代碼庫中分散如下代碼。

try 
{ 
  runABunchOfMethods(); 
} 
catch (Exception ex) 
{ 
  logger.Log(ex); 
} 

我建議你首先看一下像這樣的代碼的實際需要。 在所有情況下,您應該捕獲一個非常特殊的異常(與通用catch全部不同)。

之后,如果您仍然有多個方法捕獲相同的異常,那么您可以考慮在執行程序中創建多個方法來處理特定的異常類型。

暫無
暫無

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

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