2009-10-21 115 views
2

大家好,我想各地傳遞方法塊作爲參數傳遞給該建在異常處理的輔助類,但它的那些東西一個是直觀的,我想將其提交批評,見解或建議。高階函數法

我想指出了前面,這是不是我怎麼做我所有的異常處理,但也有在那裏我發現這種結構更多的情況下「可讀性」。

例如,我有一個場景,我正在顯示預覽圖像,但如果失敗(這是一個真實場景,我正在預覽圖像,某些GIF/BMP格式無法預覽),這只是一個場景,我顯示替代圖像而不是預覽。在try/catch代碼塊,看起來像這樣:

try 
    { 
     alternatePreviewImage.SetSource(fs); 
    } 
    catch (Exception ex) { 
     requiresSpecialPreview = false; 
     previewImage = new BitmapImage(new Uri("Images/NoPreviewAvailable.png", UriKind.Relative)); 
    } 

所以我會利用一個輔助類,需要一個方法參數,使它看起來像這樣:

if(!ErrorHelper.RunWithSuccessNotify(()=> alternatePreviewImage.SetSource(fs))){ 
     requiresSpecialPreview = false; 
     previewImage = new BitmapImage(new Uri("Images/NoPreviewAvailable.png", UriKind.Relative));        
    } 

的ErrorHelper.RunWithSuccessNotify是很簡單:

public static bool RunWithSuccessNotify(Action code) { 
    bool success = true; 
    try 
    { 
     code(); 
    } 
    catch (Exception ex) 
    { 
     success = false; 
    } 

    return success; 
} 

讓我再次強調,這是對這些低撞擊場景,以及在那裏我也許能抑制異常有用的人:

public static void RunWithErrorSuppression(Action code) { 
    try 
    { 
     code(); 
    } 
    catch (Exception ex) 
    { 
     // pass 
    } 
} 

該方法可以更細緻也允許捕獲異常:

public static void ExecuteWithLogging(Action code, Action<Exception> handles) { 
     try 
     { 
      code(); 
     } 
     catch (Exception ex) 
     { 
      handles(ex); 
     } 
    } 

那麼,什麼是這套戰術的集中異常處理的想法?如果這是一個糟糕的方向,有什麼具體原因可能導致我陷入麻煩?

回答

0

你好,我不知道它是否很好地擴展,但現在我的團隊是在我們的測量軟件用它來處理特殊的例外(如一些測量設備通信丟失),然後重新啓動在這種情況下測量。

現在它的工作很好,特別是在情況下,代碼的重要/非重複的部分是在函數(Action參數)被調用,並在異常處理不是真的。

最好的情況是,它們甚至可以是嵌套的並且主代碼保持可讀的。

另一方面,你正在隱藏你的異常處理在函數名後面做了什麼,所以它應該是簡單的或足夠清楚的,只需通過函數的名稱就可以理解,否則你是在混淆未來的某些東西代碼的讀者(包括你自己)

3

我會用這種方法捕獲Exception的主要問題通常被認爲是不好的形式。如果有某種方法可以指定要捕獲哪種類型的異常,我可能會購買它,但我相信必須在編譯時指定。對於捕捉所有例外情況並重新推出不匹配的例外情況,我也感到不太舒服。

記住,當你發現一個異常,你基本上說,你可以在一些有意義的方式處理錯誤。很顯然,上面的代碼無法處理StackOverflowExceptionMissingMethodException

+0

小細節:除非您自己拋出,否則在近期版本的框架中無法捕捉到'StackOverflowException'。 – Joren 2009-10-21 21:46:35

+2

您可以在其中指定預期異常的通用版本 – 2009-10-21 21:50:54

+1

Vinko的好處,儘管我仍然沒有看到該解決方案如何更易於維護,表達,可讀或高性能。 (是的,我故意將性能放在最後。) – Lee 2009-10-21 22:05:12

-1

如果我明白你想要做什麼,然後感覺太可怕了我作爲一個標準誤差的管理模式。那是一個警告信號,因爲我花了一段時間來掌握你的想法。

除非有一個很好的理由,代碼應該在明確的方法可用於任何維護開發人員可以查看和修改,而不是從其他地方傳來傳去。僅僅因爲某個功能的存在並不意味着它在大多數情況下都很有用。在這種情況下,我看不到混淆的好處。

順便說一句,我認爲你是nailing the corpse to the wall by catching System.Exception。通常的規則是不要捕獲異常,除非您知道異常是什麼和/或出於某種原因需要了解異常詳細信息。

在未知異常情況下的恢復

一個常用的模式看起來是這樣的:

bool exceptionHappened = true; 
try 
{ 
    alternatePreviewImage.SetSource(fs); 
    exceptionHappened = false; 
} 
finally 
{ 
    if (exceptionHappened) 
    {  
     requiresSpecialPreview = false; 
     etc; 
    } 
} 
+0

這樣的finally {if(expcetionHappened){..}}與捕獲異常有什麼不同?可以拋出一些不是從異常派生的東西嗎? – harms 2009-12-11 13:08:57

+0

在不需要這樣做的情況下捕獲異常的問題是,您必須吞下異常(通常不好),或者必須重新拋出異常。 Catch-rethrow擾亂了異常雙通機制,因此給出了一個悲慘的調試體驗。 – RoadWarrior 2009-12-11 16:45:09

0

我最初的想法很簡單,就是通過複雜的匿名委託周圍味道不好。沒有任何東西阻止某人將具有複雜邏輯的匿名代理轉儲到ErrorHelper方法中。這樣的邏輯變得難以測試。我寧願只在一個對象中傳遞邏輯,這對我來說似乎是一個更好理解的技術。對我來說,匿名代理(和lambda)是非常簡單的邏輯可擴展性,就像比較邏輯一樣。匿名代表的機制是強大的,可以用於其他事情,但擁有巨大的權力會帶來巨大的責任。 =)

用您的技術實現的是在運行時乾淨地更改異常處理策略的能力。但這是一個實際的要求嗎?

+1

Lambdas比簡單的邏輯有更多的用途。創造性思考。 – ChaosPandion 2009-10-21 22:04:49

+1

啊,謝謝你的指導。我從來沒有想過要想出來。我會開始這樣做。 呵呵,當然lambda有更多的用處。這是否意味着所有可能的系統性脫鉤都應該通過使用lambda來實現?沒門。在大多數情況下,我認爲面向對象的依賴注入仍然更好。在箱子外面想想。 – 2009-10-21 22:08:50

0

看一看THIS,也許馬上拿出就可以了醇」反射了一下。在我看來,喜歡同樣的事情完成,但有可能以更完整的方式......這似乎很強大...

1

不要捕獲所有異常,參數化一個你想要的:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ProvaException 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      int a = doWithException<int>(divide, 0, typeof(DivideByZeroException), x => 300); 
      Console.WriteLine(a); 
      Console.ReadKey(); 
     } 

     public static int divide(int b) 
     { 
      return 10/b; 
     } 

     public static T doWithException<T>(Func<T, T> a, T param1, Type exType, Func<Exception, T> handFunction) { 
      try 
      { 
       return a(param1); 
      } 
      catch(Exception ex) { 
       if(exType.Equals(ex.GetType())) { 
        return handFunction(ex); 
       } 
       else 
        throw ex; 
      } 
     } 
    } 
} 

不是非常類似C#,但它可以用於相同的情況(當你想抽象處理異常)。

你必須寫爲每一種功能的不同類型的簽名,因爲C#不支持鑽營。 Veeeeeeeeery無聊。 :d

這不是一個很優雅的解決方案,但它給你的東西是如何工作的函數式語言的暗示。學習很有趣。