Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Here is a code I want to simplify:

public void Method1(Context context, EventLog log = null)
{
    Class myClass = ConvertToMyClass();
    ApiCall1 apiCall = new ApiCall1(context);
    if (log != null)
    {
        eventLog.WriteEntry("Starting");
    }

    try
    {
        apiCall.Call1(myClass, null, false);
        IsCallSuccess = true;
    }
    catch (Exception e)
    {
        if (log != null)
        {
            eventLog.WriteEntry("error");
        }

        IsCallSuccess= false;
        CallErrorMessage = e.Message;
    }
}

public void Method2(Context context, EventLog log = null)
{
    Class myClass = ConvertToMyClass();
    ApiCall2 apiCall = new ApiCall2(context);
    if (log != null)
    {
        eventLog.WriteEntry("Starting");
    }

    try
    {
        apiCall.Call1(myClass);
        NewItemID = myClass.ItemID;
        IsCallSuccess = true;
    }
    catch (Exception e)
    {
        if (log != null)
        {
            eventLog.WriteEntry("error");
        }

        IsCallSuccess= false;
        CallErrorMessage = e.Message;
    }
}

public void Method3Context context, EventLog log = null)
{
    Class myClass = ConvertToMyClass();
    ApiCall3 apiCall = new ApiCall3(context);
    if (log != null)
    {
        eventLog.WriteEntry("Starting");
    }

    try
    {
        apiCall.Call3(myClass, "param1");
        UpdatedItemID = myClass.UpdatedItemID;
        IsCallSuccess = true;
    }
    catch (Exception e)
    {
        if (log != null)
        {
            eventLog.WriteEntry("error");
        }

        IsCallSuccess= false;
        CallErrorMessage = e.Message;
    }
}

There are 3 methods. I've been thinking about how I could simplify them using delegates or lambdas and didn't find anything.

Note that ApiCall1/2/3 are all defined in a third-party library. Your thoughts?

share|improve this question
Do ApiCall1/2/3 all implement the same base class or interface? – Michael Perrenoud Oct 25 '12 at 11:42
Yes, they do... – Alan Dert Oct 27 '12 at 16:03

2 Answers

Alright, let's see if we can simplifyabstract this for you. I'm not going to say simplify because often times abstracting something is far from simplifying it.

I think you can turn the method into something like this:

public void Method<T>(Context context, Action<T, Class> body, EventLog log = null)
{
    Class myClass = ConvertToMyClass();
    T apiCall = Activator.CreateInstance(typeof(T), new [] { context });
    if (log != null)
    {
        eventLog.WriteEntry("Starting");
    }

    try
    {
        body(apiCall, class);
        IsCallSuccess = true;
    }
    catch (Exception e)
    {
        if (log != null)
        {
            eventLog.WriteEntry("error");
        }

        IsCallSuccess = false;
        CallErrorMessage = e.Message;
    }
}

... then you should be able to call it like this:

// Method1
Method<ApiCall1>(
    yourContextInstance,
    (apiCall, myClass) =>
    {
        apiCall.Call1(myClass, null, false);
    },
    yourLogInstance);

// Method2
Method<ApiCall2>(
    yourContextInstance,
    (apiCall, myClass) =>
    {
        apiCall.Call1(myClass);
        NewItemID = myClass.ItemID;
    },
    yourLogInstance);

// Method3
Method<ApiCall3>(
    yourContextInstance,
    (apiCall, myClass) =>
    {
        apiCall.Call3(myClass, "param1");
        UpdatedItemID = myClass.UpdatedItemID;
    },
    yourLogInstance);

... one caveat is NewItemID and UpdatedItemID. If you're not making these calls from inside the class Method is defined in, you may need to modify this a tad to get the Method to return and integer instead.

share|improve this answer
Instead of Activator.CreateInstance(), you could use another delegate to make it more type-safe. – svick Oct 27 '12 at 11:58
I agree with svick. – Alan Dert Oct 27 '12 at 16:05

BigM's solution seems like what you are after but here's just another alternative using the Template pattern.

NOTE: I wrote this in Notepad so it might not be 100% compilable :)

internal abstract class MethodHandler {

   private readonly EventLog _log { get; private set; }

   public bool IsCallSuccess { get; private set; }
   public string CallErrorMessage { get; private set; }

   protected MethodHandler()
      : this(null)
   {
   }   

   protected MethodHandler(EventLog log) 
   {
      Log = log;
   }

   protected void LogEvent(string message)
   {
      if(_log != null) 
        _log.WriteEntry("Starting");
   }

   public void Execute(Context context) 
   {    
        try
        {       
            LogEvent("Starting");   
            Class myClass = ConvertToMyClass();     

            CallApi(context, myClass);
            IsCallSuccess = true;
        }
        catch (Exception e)
        {
            // if we are logging here we should really log the exception as well
            LogEvent("error");

            IsCallSuccess= false;
            CallErrorMessage = e.Message;
        }   
   }

   protected abstract CallApi(Context context, Class myClass);
}

internal class MethodHandler1 : MethodHandler
{
   public MethodHandler1(EventLog log) 
    : base(log)
   {
   }

   protected override CallApi(Context context, Class myClass)
   {
       ApiCall1 apiCall = new ApiCall1(context);    
       apiCall.Call1(myClass, null, false);    
   }
}

internal class MethodHandler2 : MethodHandler
{
   public MethodHandler2(EventLog log) 
    : base(log)
   {
   }

   protected override CallApi(Context context, Class myClass)
   {   
       new ApiCall2(context).Call1(myClass);
       NewItemID = myClass.ItemID;
   }
}

public static class MethodHandlerFactory
{
    public MethodHandler CreateHandler(EventLog log = null)
    {
       if(/* Handler 1 */)
         return new MethodHandler1(log);
       // etc
    }
}
share|improve this answer
CallApi is defined in another library, I can't modify it. – Alan Dert Oct 27 '12 at 16:06

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.