通过多态性处理异常

时间:2011-06-14 07:14:41

标签: .net wcf oop

我在这个设计中需要一个观点,我建议处理异常。

我有一个wcf服务,它会抛出不同类型的错误异常:

  1. 抛出新的FaultException< BusinessRuleViolationFault>(...)
  2. 抛出新的FaultException< SomeOtherViolationFault>(...)
  3. ...
  4. ...
  5. 所有这些错误异常类都实现了一个名为IViolationFault的接口,该接口只有一个HandleException方法。每种这样的方法的实现取决于它们所在的类别;所以例如当客户端捕获这些异常类时,我需要做的只是调用HandleException()方法,并且我将不必编写IF条件来区分错误类型。在BusinessRuleViolationFault的HandleException()方法中,我可能只想在屏幕上显示一条消息,而在另一个方面我可能想在某处记录它并触发其他一些操作......

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

    问题

    1. 这有什么不妥吗? 方法
    2. 有没有办法可以减少 捕获块的数量和刚刚 一个catch块可以处理所有异常类型吗?
    3. 在处理异常时,这是一种很好的面向对象的方法来实现多态吗?
    4. 修改

      我已将代码更改为从基类继承而不是实现接口。我的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();
      }
      

      请让我对此有所了解。谢谢你的时间......

3 个答案:

答案 0 :(得分: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;
    }

}

答案 1 :(得分: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();
}

答案 2 :(得分:-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");
    });