views:

73

answers:

3

Suppose I have a .NET assembly, A, which uses reflection to load assemblies B and C (also .NET). These two assemblies both implement a number of large interfaces (the same for both). When a method is called in A it tries to make B do the work. However, B is unreliable and might throw exceptions. Now A has two modes, one where it propagates the exceptions out to the caller of A and one where it calls matching methods on the more stable (but less performant) C.

Are there better ways (less code) to implement this scenario than wrapping all the methods B exposes in a huge implementation of all B's interfaces, only now surrounding every call with code as shown below? The assemblies B and C don't know anything about the error handling approach chosen, so they can't implemet the logic.

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);
      }
   }
   ...
}
+1  A: 

You might do this, it saves some repetition:

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);
      }
   }
   ...
}
1800 INFORMATION
+1  A: 

Hmmm... to save some code you could wrap most of the common signatures via delegates, like below (note I've only included the core bits to keep it clear - but you can add your FailWithExceptions stuff trivially):

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

Then you can re-use this for implementations via:

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

Obviously you could add a few signatures for related code, such as:

    static TResult TryWithFallback<T, TResult>(Func<T, TResult> primary, Func<T, TResult> fallback, T arg)
    {
        try
        {
            return primary(arg);
        }
        catch
        {
            return fallback(arg);
        }
    }
Marc Gravell
+1  A: 

I suggest that you look at using reflection and System.CodeDom to generate the code. I had a similar problem recently when I was trying to write a wrapper for a COM interop assembly that had a very large interface with lots of methods with signatures that contained parameter types that I did not want to use on the client side but which I could easily convert to the types I did want on the client side. They were also 'ref' parameters which would make the client code more verbose. The methods had varying numbers of parameters with meaningful names that I wanted to expose on the client side.

Write a base class for your wrapper that has members for an instance of A and B. Write a code generation class that generates a derived wrapper class. The code generation should then iterate over the methods for each interface that the wrapper should implement and add a method and method body with appropriate code to call A and B within your required error handling construct. The code you generate to call A and B will be dependant on the signature of the method you are calling but this is not hard to achieve by iterating over that parameters of the method being generated or called.

I could post my code but as I am doing something slightly different I think that you are better going back to MSDN or other public samples. All I can say is that I found this surprisingly straightforward and robust.

I suggest that you check in your code generation code rather than the generated code and run the code generation as part of your build.