大型接口的统一错误处理

时间:2008-11-19 09:24:46

标签: c# .net error-handling

假设我有一个.NET程序集A,它使用反射来加载程序集B和C(也是.NET)。这两个程序集都实现了许多大型接口(两者都相同)。当在A中调用方法时,它试图使B完成工作。但是,B不可靠,可能会抛出异常。现在A有两种模式,一种是将异常传播给A的调用者,另一种是在更稳定(但性能较差)的C上调用匹配方法。

实现这种场景是否有更好的方法(更少的代码),而不是将所有方法B暴露在所有B接口的大量实现中,现在只围绕每个使用代码的调用,如下所示?程序集B和C对所选的错误处理方法一无所知,因此无法实现逻辑。

public class BErrorWrapper : I1, I2, I3{
   ...
   public int DoSomeWork(int num){
      if (FailWithExceptions)
      {
         try
         {
            return B.DoSomeWork(num);
         }
         catch(MyLibException e)
         {
            return C.DoSomeWOrk(num);
         }
      }
      else
      {
         return B.DoSomeWork(num);
      }
   }
   ...
}

3 个答案:

答案 0 :(得分:2)

你可以这样做,它可以节省一些重复:

public class BErrorWrapper : I1, I2, I3{
   ...
   public int DoSomeWork(int num){
      try
      {
         return B.DoSomeWork(num);
      }
      catch(MyLibException e)
      {
         if (FailWithExceptions) throw;
         return C.DoSomeWOrk(num);
      }
   }
   ...
}

答案 1 :(得分:1)

嗯......要保存一些代码,你可以通过委托来包装大多数常见签名,如下所示(注意我只包括核心位以保持清晰 - 但你可以添加你的FailWithExceptions东西平凡):

    static void TryWithFallback<T>(Action<T> primary, Action<T> fallback, T arg)
    {
        try
        {
            primary(arg);
        }
        catch // add your other regular code here...
        {
            fallback(arg);
        }
    }

然后您可以通过以下方式重新使用它来实现:

    TryWithFallback(b.DoSomeWork, c.DoSomeWork, num);

显然,您可以为相关代码添加一些签名,例如:

    static TResult TryWithFallback<T, TResult>(Func<T, TResult> primary, Func<T, TResult> fallback, T arg)
    {
        try
        {
            return primary(arg);
        }
        catch
        {
            return fallback(arg);
        }
    }

答案 2 :(得分:1)

我建议你看看使用反射和System.CodeDom来生成代码。我最近有一个类似的问题,当我试图为COM互操作程序集编写一个包装器时,它有一个非常大的接口,有很多方法,签名包含我不想在客户端使用的参数类型,但我可以很容易转换为我在客户端想要的类型。它们也是'ref'参数,这将使客户端代码更加冗长。这些方法有不同数量的参数,我想在客户端公开有意义的名称。

为包装器编写一个基类,该包装器具有A和B实例的成员。编写一个生成派生包装类的代码生成类。然后,代码生成应该迭代包装器应该实现的每个接口的方法,并添加一个方法和方法体,并使用适当的代码在您需要的错误处理构造中调用A和B.生成的用于调用A和B的代码将取决于您调用的方法的签名,但通过迭代生成或调用的方法的参数并不难实现。

我可以发布我的代码,但由于我做的事情略有不同,我认为你最好回到MSDN或其他公共示例。我只能说,我发现这个令人惊讶的直截了当且坚固。

我建议您检查代码生成代码而不是生成的代码,并在构建过程中运行代码生成。