C# 大型接口的统一错误处理

C# 大型接口的统一错误处理,c#,.net,error-handling,C#,.net,Error Handling,假设我有一个.NET程序集a,它使用反射加载程序集B和C(也是.NET)。这两个程序集都实现了许多大型接口(两者都相同)。当一个方法在a中被调用时,它试图让B完成这项工作。但是,B是不可靠的,可能会抛出异常。现在A有两种模式,一种是将异常传播到A的调用方,另一种是在更稳定(但性能较差)的C上调用匹配方法 是否有更好的方法(更少的代码)来实现这个场景,而不是将B公开的所有方法包装在所有B接口的一个巨大实现中,只是现在用如下所示的代码围绕每个调用?程序集B和C对所选择的错误处理方法一无所知,因此无法

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

您可以这样做,这样可以避免一些重复:

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

嗯。。。要保存一些代码,您可以通过代理包装大多数常见签名,如下所示(注意,为了保持清晰,我只包含了核心部分,但您可以简单地添加
FailWithExceptions
内容):

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

    static TResult TryWithFallback<T, TResult>(Func<T, TResult> primary, Func<T, TResult> fallback, T arg)
    {
        try
        {
            return primary(arg);
        }
        catch
        {
            return fallback(arg);
        }
    }
static TResult trywhithfallback(Func primary、Func fallback、T arg)
{
尝试
{
返回主(arg);
}
抓住
{
返回回退(arg);
}
}

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

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

我可以发布我的代码,但由于我正在做一些稍微不同的事情,我认为您最好返回MSDN或其他公共示例。我所能说的是,我发现这一点令人惊讶地直截了当和强大

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

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