【问题标题】:Uniform error handling of large interfaces大型接口的统一错误处理
【发布时间】:2010-09-23 00:23:25
【问题描述】:

假设我有一个 .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);
      }
   }
   ...
}

【问题讨论】:

    标签: c# .net error-handling


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      嗯...要保存一些代码,您可以通过委托包装大多数常见签名,如下所示(请注意,我只包含核心位以保持清晰 - 但您可以添加您的 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);
              }
          }
      

      【讨论】:

        【解决方案3】:

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

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

        我可以发布我的代码,但由于我正在做一些稍微不同的事情,我认为您最好回到 MSDN 或其他公共示例。我只能说,我发现这出奇的简单和健壮。

        我建议您签入您的代码生成代码而不是生成的代码,并将代码生成作为构建的一部分运行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-09
          • 2017-10-14
          • 2014-11-25
          相关资源
          最近更新 更多