2010-12-16 25 views
2

有問題的代碼是由機器人(CodeSmith)編寫的,這是一個很難維護的問題。它看起來有點類似:如何在方法調用中添加常用功能?

public AddressProgramTemplate GetById(System.Int32 _id) { 
    try { 
     return Service.GetById(_id); 
    } catch (FaultException<ErrorInfo> ex) { 
     throw new ProxyServerBusinessException(ex.Detail); 
    } catch (FaultException) { 
     throw new ProxyServerBusinessException(null); 
    } catch (EndpointNotFoundException ex) { 
     throw new ProxyServerTechnicalException<EndpointNotFoundException>(ex); 
    } catch (CommunicationObjectFaultedException ex) { 
     throw new ProxyServerTechnicalException<CommunicationObjectFaultedException>(ex); 
    } catch (CommunicationException ex) { 
     throw new ProxyServerTechnicalException<CommunicationException>(ex); 
    } catch (ObjectDisposedException ex) { 
     throw new ProxyServerTechnicalException<ObjectDisposedException>(ex); 
    } catch (TimeoutException ex) { 
     throw new ProxyServerTechnicalException<TimeoutException>(ex); 
    } 
} 

正如您可以猜到,這是一個客戶端WCF代理代碼,並重復每一個服務方法有所有這些行(並且有很多)。機器人的好處對我來說是一種悲傷,所以我開始重構它。首先,異常邏輯和處理委託給微軟企業庫和通用代碼遷移到基類:

public TResult WrapServiceMethod<TResult>(Func<TResult> serviceMethod) { 
    TResult result = default(TResult); 
    try { 
     result = serviceMethod(); 
    } catch (Exception ex) { 
     bool rethrow = ExceptionManager.HandleException(ex, ExceptionPolicyNames.ClientRequestPolicy); 
     if (rethrow) throw; 
    } 
    return result; 
} 

到目前爲止好,醜的try/catch堆變成了整潔的一行代碼:

return WrapServiceMethod<AddressProgramTemplate>(() => Service.GetById(_id)); 

有一點努力和無效的方法也包括在內。問題是當服務呼叫使用out參數:在

public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate){ 
    WrapServiceMethod(() => Service.GetPeriod(program, out startDate, out endDate)); 
} 

結果「不能使用ref或out參數‘結束日期’匿名方法,lambda表達式或查詢表達式內」,我理解why

我會非常想有是定義運營商定製模塊,如同時使用()的能力()或者,我可以寫

wrapexception { ... } 

並且永遠幸福地生活在一起,但我不」 t認爲這個技巧是可能的。假設沒有out參數重寫所有服務方法是不得已而爲之,我是否還有其他選擇?

回答

2

聽起來就像是在面向方面的編程庫(如PostSharp)之後。

您可以創建插入您的IL基於規則的編譯後您指定哪些可以做的事情,如捕捉異常,記錄,跟蹤等

這樣做的好處異常處理程序是你寫的方面一次,並將其應用於多種方法。這些方法不會混淆與特定任務無關的代碼,因爲橫切問題(如異常處理)由方面來處理。

查看http://www.sharpcrafters.com/solutions/monitoring#exception-monitoring的示例,其中顯示瞭如何處理異常。

+0

看起來前途 - 一個機器人修改編譯的程序集而不是源代碼。確實應該更容易維護。有沒有嚴重的性能缺陷? – 2010-12-16 23:55:26

+0

應該指出並不是所有的AOP庫都是後編譯的。 PostSharp是,但其他人不修改編譯的程序集。除非你寫出一個狡猾的方面,否則性能不應該受到影響。像往常一樣,簡介和比較可以肯定。 Spring.NET使用代理對象來創建方法攔截器作爲實現AOP的方式。 – 2010-12-16 23:58:31

+0

我很可能會從微軟企業庫的PolicyInjection中僅僅因爲它是微軟(易於銷售),並且它已經在我們的項目中使用(更容易銷售)。 – 2010-12-18 22:17:32

1

來改變out簽名(因而不必改變所有的調用代碼,這一點我敢肯定,你想避免),你可以做這樣的事情的另一種:

public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate) 
{ 
    var outs = WrapServiceMethod(() => 
     { 
      DateTime sd; 
      DateTime ed; 
      Service.GetPeriod(program, out sd, out ed)); 
      return new {sd, ed}; 
     } 
    startDate = outs.sd; 
    endDate = outs.ed; 
} 
+1

優秀小費,非常感謝!將其作爲一個快速修復,直到完整的AOP實現被授予綠燈。 – 2010-12-18 22:14:19