2011-06-14 86 views
2

我需要一個在這個設計中的觀點,我提出處理異常。通過多態的異常處理

我有拋出不同類型的故障異常的WCF服務:

  1. 拋出新的FaultException < BusinessRuleViolationFault>(...)
  2. 拋出新的FaultException < SomeOtherViolationFault>(...)
  3. ...
  4. ...

所有這些故障excep tion類實現了一個叫做IViolationFault的接口,它有一個HandleException方法。每個這樣的方法的實現取決於它們所處的類別而不同;所以例如當這些異常類在客戶端中被捕獲時,我所需要做的就是調用HandleException()方法,並且不需要編寫IF條件來區分這些類型的錯誤。在BusinessRuleViolationFault的HandleException()方法,我可能只是想在屏幕上顯示的消息,而在另外一個我可能要到什麼地方登錄,並引發一些其他的動作,以及...

catch (FaultException<BusinessRuleViolationFault> ex) 
{ 
ex.HandleException(); 
} 
catch (FaultException<SomeOtherViolationFault> ex) 
{ 
ex.HandleException(); 
} 

問題

  1. 這個 方法有什麼不對嗎?
  2. 有沒有一種方法可以減少catch塊的數量 並且只需要一個catch塊來處理所有異常類型?
  3. 這是一個很好的面向對象的方式來處理異常時獲得多態嗎?

EDIT

伊夫改變了代碼以從基類繼承,而不是實施的接口。我的BusinessRuleViolationFault類具有HandleException方法,但我無法獲取客戶端catch塊中的HandleException方法。什麼做錯了?這是它是如何在服務

BusinessRuleViolationFault bf = new BusinessRuleViolationFault(""); 
throw new FaultException<BusinessRuleViolationFault>(bf, new FaultReason(new FaultReasonText("Fault reason here"))); 

拋出這是我BusinessRuleViolationFault代碼

[DataContract] 
public class BusinessRuleViolationFault : BaseFault 
{ 
    public BusinessRuleViolationFault(string message) 
     : base(message) 
    { 

    } 


    [OperationContract] 
    public override string HandleException() 
    { 
     return "BusinessRuleViolationFault executed"; 
    } 
} 



[DataContract] 
public abstract class BaseFault 
{ 
    public BaseFault(string message) 
    { 
     Message = message; 
    } 

    [DataMember] 
    public string Message { get; set; } 

    [OperationContract] 
    public abstract string HandleException(); 
} 

不要讓我有你的這個想法。感謝您的時間...

+0

爲什麼在異常上使用泛型?它如何讓生活更輕鬆? – 2011-06-14 08:01:08

+0

@Yves M.這個問題被標記爲_wcf_。在WCF中使用['FaultException '](http://msdn.microsoft.com/zh-cn/library/ms576199.aspx)是實現錯誤合同的方式。 – 2011-06-14 10:27:48

+0

'[DataContract]內的'[OperationContract]'是毫無意義的。你真的需要閱讀WCF基礎知識 - 抱歉。 – 2011-06-14 15:59:52

回答

1

編輯:正確示例代碼。

至少在WCF中,這是實現自定義錯誤的方式,這樣做沒有任何問題。儘管如此,你不能這樣做,因爲你不能這樣

// Does not work 
try 
{ 
} 
catch (FaultException<IVoliationFault> ex) 
{ 
    ex.HandleException(); 
} 

捕獲你的FaultExceptions。

你也(顯然)不能更改基類System.ServiceModel.FaultException<TDetail>甚至System.ServiceModel.FaultException以包括任何HandleException()方法。

你可以做的是,用反射上班提取的FaultException的TDetail,如果有的話,然後與工作:

 try 
     { 
     } 
     catch (FaultException ex) 
     { 
      var detail = ex.GetDetail<IViolationFault>(); // EDIT: Specify type 

      if (detail != null) 
      { 
       detail.HandleException(); 
      } 
      else 
      { 
       // Either not a FaultException<TDetail>, or not FaultException<IViolationFault>. 
       throw; 
      } 
     } 
... 

public static class FaultExceptionExtensions 
{ 
    public static T GetDetail<T>(this FaultException exception) 
    { 
     if (exception == null) 
      throw new ArgumentNullException("exception"); 

     Type type = exception.GetType(); // EDIT: use "exception" instead of "ex" 
     if (!type.IsGenericType) 
     { 
      return default(T); 
     } 

     Type genType = type.GetGenericArguments()[0]; 

     PropertyInfo pi = type.GetProperty("Detail", genType); 
     Debug.Assert(pi != null, "FaultException<" + genType + ">.Detail property is missing"); 

     object val = pi.GetValue(exception, null); 

     if (!typeof(T).IsInstanceOfType(val)) 
     { 
      return default(T); 
     } 

     return (T)val; 
    } 

} 
+0

這一行「var detail = ex.GetDetail()as IViolationFault;」 catch塊中的FaultException類型的對象上沒有GetDetail方法。我試過GetType(),但得到一個錯誤,說它不會轉換..我錯過了什麼? ...謝謝。 – user20358 2011-06-14 10:59:46

+0

@ user20358請看完整的答案。我在'FaultExceptionExtensions'類中提供了一個樣例實現作爲擴展方法。 – 2011-06-14 11:49:48

+0

謝謝。試過了。在另一個命名空間中創建了FaultExceptionExtensions類,但出現此錯誤「方法'MyExtension.FaultExceptionExtensions.GetDetail (System.ServiceModel.FaultException)'的類型參數不能從該用法中推斷出來,請嘗試明確指定類型參數。 ..我是新來的,所以可能錯過了這裏的東西..任何想法是什麼cud是錯的? – user20358 2011-06-14 12:55:07

0

這種方法沒有什麼錯,它只是一個正常使用多態性。

您可以通過讓所有自定義異常類從基本異常類派生而不是僅實現接口來減少catch塊的數量。例如:

public abstract class FaultException : Exception 
{ 
    public abstract void HandleException() 
} 

public class Faultexception<T> : FaultException 
{ 
    public override void HandleException() 
    { 
     //your code here 
    } 
} 

這樣你就可以趕上只以下的所有異常:

catch (FaultException ex) 
{ 
    ex.HandleException(); 
} 
+0

我很抱歉..我不太明白這條線「public class Faultexception :FaultException」將與這條線一起工作「catch(FaultException ex)」..how catch知道哪種類型的異常被拋出? – user20358 2011-06-14 10:06:14

+0

另外,如果在服務中拋出BusinessRuleViolationFault,那麼這個catch塊如何執行BusinessRuleViolationFault的HandleException()方法,以及在客戶端中的相同catch塊如何執行SomeOtherViolationFault的HandleException()方法來處理異常被拋出。 – user20358 2011-06-14 10:16:27

-1

你可能想看看記錄功能的方法在this blog post,它允許你使你的try/catch邏輯更清晰簡潔一點。 例如:

TryCatch.Try(() => 
     { 
      using (var stream = File.OpenRead(FileTextBox.Text)) 
      { 
       Trace.WriteLine(stream.Length); 
      } 
     }) 
.Catch<FileNotFoundException, 
    DirectoryNotFoundException, 
    UnauthorizedAccessException> 
    (ex => 
    { 
     MessageBox.Show(ex.Message, "Fail"); 
    });