2011-06-14 7 views
2

이 디자인에서는 예외 처리를 제안하고 있습니다.다형성을 통한 예외 처리

  1. 던져 새로운 오류 예외 < BusinessRuleViolationFault> (...)
  2. 던져 새로운 오류 예외 < SomeOtherViolationFault> (...)
  3. :

    나는 다른 오류 예외의 유형을 던졌습니다 WCF 서비스를 excep

  4. ...
  5. ...

이 모든 결함 클래스는 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 메서드를 가져올 수 없습니다. 무엇이 잘못 되었습니까? 이는이 날이에 대한 당신의 생각을하자 DO 내 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(); 
} 

인 서비스

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

에 슬로우됩니다 방법이다. 시간 내 주셔서 감사합니다 ...

+0

왜 예외로 제네릭을 사용하고 있습니까? 어떻게하면 더 쉽게 살 수 있습니까? –

+0

@ Yves M. 질문에 _wcf_ 태그가 지정되었습니다. ['FaultException '] (http://msdn.microsoft.com/en-us/library/ms576199.aspx)을 사용하는 WCF에서 오류 계약을 구현하는 방법입니다. –

+0

'[DataContract] 내부의'[OperationContract]'는 무의미합니다. WCF 기본 사항을 읽어야합니다. - 죄송합니다. –

답변

1

편집 : 올바른 샘플 코드 예를 들어.

적어도 WCF에서 사용자 지정 오류를 구현하는 방법은 어디에도 없습니다. 비록 당신이 다형성을 잃어 버렸지 만, 이런 식으로는 할 수 없듯이, FaultExceptions를 잡기 위해서는

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

을 잡아라.

기본 클래스 System.ServiceModel.FaultException<TDetail> 또는 심지어 System.ServiceModel.FaultExceptionHandleException() 메서드를 포함하도록 변경할 수 없습니다 (분명히).

당신이 할 수있는 일은 어떤 경우 오류 예외의 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

+0

@ user20358 전체 답변을 살펴보십시오. 나는'FaultExceptionExtensions' 클래스의 확장 메소드로서 샘플 구현을 제공합니다. –

+0

감사합니다. 그거야. 다른 네임 스페이스에 FaultExceptionExtensions 클래스를 만들었지 만 "이 메서드에서 'MyExtension.FaultExceptionExtensions.GetDetail (System.ServiceModel.FaultException)'의 형식 인수를 유추 할 수 없습니다. 명시 적으로 형식 인수를 지정하십시오." .. 나는 이것에 익숙하지 않을 것입니다. 아마 여기 뭔가 빠져 있습니다. 어떤 생각이 틀렸습니까? – user20358

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)"와 어떻게 작동하는지 이해하지 못했습니다. catch는 어떤 유형의 예외가 발생했는지 알 수 있습니까? – user20358

+0

또한 BusinessRuleViolationFault가 서비스에서 throw되고 해당 예외가 throw 된 경우 클라이언트의 동일한 catch 블록이 SomeOtherViolationFault의 HandleException() 메소드를 실행하면 해당 catch 블록이 BusinessRuleViolationFault의 HandleException() 메소드를 어떻게 실행합니까? – user20358

-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"); 
    });