2010-06-17 67 views
7

使用.NET框架我有一系列可以生成多種類型異常的方法的服務:MyException2,MyExc1,Exception ...爲所有人提供適當的工作方法,他們每個人都包含以下幾個部分:如何避免異常捕獲.NET中的複製粘貼

[WebMethod] 
void Method1(...) 
{ 
    try 
    { 
     ... required functionality 
    } 
    catch(MyException2 exc) 
    { 
     ... process exception of MyException2 type 
    } 
    catch(MyExc1 exc) 
    { 
     ... process exception of MyExc1 type 
    } 
    catch(Exception exc) 
    { 
     ... process exception of Exception type 
    } 
    ... process and return result if necessary 
} 

這是很無聊的用完全相同的異常處理功能,具有完全相同的東西,在每個服務方法(每種方法都有不同的參數)...

是否有可能將這些catch部分「分組」並僅使用一行(與C++宏類似)?可能.NET 4.0中的新東西與此主題有關?

謝謝。

P.S.任何想法都歡迎。

回答

6

如果異常處理正是在您所有的方法都是一致的,你可以這樣做:

void CallService(Action method) 
{ 
    try 
    { 
     // Execute method 
     method(); 
    } 
    catch(MyException2 exc) 
    { 
     ... process exception of MyException2 type 
    } 
    catch(MyExc1 exc) 
    { 
     ... process exception of MyExc1 type 
    } 
    catch(Exception exc) 
    { 
     ... process exception of Exception type 
    } 
} 

然後,你可以只重寫你的客戶端代碼做:

int i = 3; 
string arg = "Foo"; 
this.CallService(() => this.Method1(i)); 
this.CallService(() => this.Method2(arg, 5)); 

這使您的Method1和Method2方法變得簡單:

void Method1(int arg) 
{ 
    // Leave out exception handling here... 
    ... required functionality 
    ... process and return result if necessary 
} 

void Method2(string stringArg, int intArg) 
{ 
    // Leave out exception handling here... 
    ... required functionality 
    ... process and return result if necessary 
} 
+0

我也有類似的想法,但問題是,每種方法都有不同的參數(對不起,我沒有提到,在原來的問題,並添加說明最近)。以下是方法簽名的示例:string Method1(string);方法二無效(字符串,INT,INT),等等... – Budda 2010-06-17 18:56:37

+0

@Budda:這並不重要 - 它會很好地工作,由於Lambda表達式可以在所有的參數傳遞,我寫它的方式。 – 2010-06-17 18:58:36

+0

@Budda:我編輯我的回答證明:)這適用於在方法的任何數量的參數... – 2010-06-17 19:00:43

-3

我知道這是不好的做法,但是如果您在每個catch語句中都有完全相同的錯誤處理,何時不只是最後一個catch語句作爲catch語句?

這當然假定您的所有異常繼承自Exception。

+0

-1:如果你知道這是一個不好的做法,那麼爲什麼推薦它? – 2010-06-17 18:36:52

+0

我不是 - 我只是好奇地想知道爲什麼你會在多個catch語句中處理完全相同的錯誤,因爲具有多個catch的點是你以不同的方式處理你的異常...... – 2010-06-17 18:39:48

+0

我有完全相同的處理以便爲所有方法提供相同的錯誤處理。 – Budda 2010-06-17 18:53:38

5

爲什麼不把代碼分解成一個輔助方法來爲你做這件事(你可以將未來需要的任何新異常添加到HandleException中,這使得它非常具有伸縮性)?

try 
{ 
    ... required functionality 
} 
catch (Exception e) 
{ 
    HandleException(e); 
    throw; // only if you need the exception to propagate to caller 
} 


private void HandleException(Exception e) 
{ 
    if (e is MyException2) 
    { 
     ... process exception of MyException2 type 
    } 
    else if (e is MyExc1) 
    { 
     ... process exception of MyExc1 type 
    } 
    else 
    { 
     ... process exception of Exception type 
    } 
} 
+0

dcp,爲什麼在調用HandleException(e)後重新拋出異常? – Budda 2010-06-17 18:58:41

+1

此模式將嚴格違反Microsoft的代碼分析規則「不捕獲一般異常類型」http://msdn.microsoft.com/zh-cn/library/ms182137(v=VS.90).aspx – chilltemp 2010-06-17 18:59:43

+3

@chilltemp - 來吧,不要重複你的自我規則有更高的優先級。 – ChaosPandion 2010-06-17 19:01:07

2

我會仔細看看你在做什麼來「處理」這些異常。很有可能你根本不需要catch塊,並且你應該允許異常傳播。

+0

這些方法是Web服務的[WebMethod],他們應該總是向客戶端返回有意義的東西。所有異常處理部分生成「錯誤」對象,該對象被序列化爲XML格式併發送給客戶端。您的建議給了我一個想法,以優化錯誤對象生成...它可以用工廠模式實現...以下列方式執行: catch(Exception exc) MyError error = MyError.GenerateErrorObject(exc); ...過程(錯誤); } 謝謝。 – Budda 2010-06-17 19:04:27

+0

@布達:1)很高興知道。下次再說。 2)你應該拋出'SoapException'的細節集來返回一個SOAP Fault。 – 2010-06-17 19:11:00

+0

我需要以某種自定義格式發送消息,並且SOAP異常不適合:) – Budda 2010-06-17 19:13:30

1

在突然間出現的怪異(並顯示你可以但可能不應該也不想做的事情):通過生成包含異常的函數,可以使整個事情更加可組合和可重用處理邏輯:

static class ExceptionHandlerExtensionMethods 
{ 
    // extend to Func<T> as desired 
    public static Action Catching<T>(this Action what, Action<T> handler) 
     where T : Exception 
    { 
     return() => 
     { 
      try 
      { 
       what(); 
      } 
      catch (T ex) 
      { 
       handler(ex); 
      } 
     }; 
    } 
} 

現在,您可以實現和重用的異常類型特定處理函數的地方,並把它們組合成一些其他的方法的異常處理。

要刪除冗餘,您可以編寫一個輔助函數,將「典型」異常處理函數添加到您想要調用的任何地方,並調用此裝飾方法。

0

從裏德·科普塞使用CallService方法:

void DoSomething(object param1, int param2) 
{ 
    this.CallService(() => 
    { 
     // work with param1 and param2 here 
    } 
} 

因爲當你需要返回一個值的情況下,你可能需要重複CallService返回一個類型參數。

T CallService<T>(Func<T> callback) { /* ... */ } 
1

我在類似情況下完成了以下操作。我將展示的技術中以兩個步驟...


步驟1.創建爲其它代碼的特定執行上下文的方法:

// this static method is responsible for setting up a context for other code 
// to run in; specifically, it provides the exception handling "plumbing": 
public static void guarded(Action action) 
{      // ^^^^^^^^^^^^^ 
    try    // actual code to be executed 
    { 
     action(); 
    } 
    catch (SomeExceptionA ea) 
    { 
     // handle exception... 
    } 
    catch (SomeExceptionB eb) 
    { 
     // handle exception... 
    } 
    // etc. 
} 

步驟2 。應用這方面的任何一段代碼:

接下來,你簡單的「包裝」這個異常周圍的行爲處理UAL代碼在你的方法:

public void MethodA() 
{ 
    guarded(() => // <-- wrap the execution handlers around the following code: 
    { 
     // do something which might throw an exception... 
    }); 
} 

public void MethodB() 
{ 
    guarded(() => 
    { 
     // do something which might throw an exception... 
    }); 
} 

摘要:

這裏的一般想法是寫(在上面的例子guarded)的功能,設置了具體的執行上下文的其他代碼(本例中的上下文提供了異常處理。)在這個上下文中執行的代碼是作爲lambda函數提供的。你甚至可以調整上下文創建函數,以便lambda函數中的代碼可以返回一個值。

+0

與Reed Copsey建議的一樣。不過謝謝你。 – Budda 2010-06-17 19:20:43

+1

糟糕。對於幾乎重複的抱歉,我不知何故設法忽略了他的答案。 **但是**注意到我們兩個答案中的細微差別:在他的回答中,外部函數顯式包裹在方法的調用者實際方法_上。我會建議,還有一些情況更適合於_let你的方法自己處理它們的上下文。他們可能比呼叫者知道哪些例外可以/必須處理。 – stakx 2010-06-17 19:27:52