How can I avoid repeated code using lambdas? I have a method which should accept a Function/Action and do something with that method (in my case I've added retry logic). 

I'm wondering how I can remove the duplicated code (for loop, etc) from the last 2 methods. Is there any clever way to do this in C#?

public static class Retry {
    public static void Do(
    Type retryOnExceptionType,
    Action action,
    TimeSpan retryInterval =
    default (TimeSpan),
    int retryCount = 3) {
        if (retryInterval ==
        default (TimeSpan)) retryInterval = TimeSpan.FromSeconds(1);

        Do &lt; object &gt; (
        retryOnExceptionType, () = &gt; {
            action();
            return null;
        }, retryInterval, retryCount);
    }

    public static T1 Do &lt; T1, T2, T3 &gt; (
    Type retryOnExceptionType,
    Func &lt; T2, T3, T1 &gt; action,
    T2 param1,
    T3 param2,
    TimeSpan retryInterval =
    default (TimeSpan),
    int retryCount = 3) {
        if (retryInterval ==
        default (TimeSpan)) retryInterval = TimeSpan.FromSeconds(1);

        var exceptions = new List &lt; Exception &gt; ();

        for (int retry = 0; retry &lt; retryCount; retry++) {
            try {
                return action(param1, param2);
            } catch (Exception ex) {
                if (!retryOnExceptionType.IsInstanceOfType(ex)) throw;

                exceptions.Add(ex);
                Thread.Sleep(retryInterval);
            }
        }

        throw new AggregateException(exceptions);
    }


    public static T Do &lt; T &gt; (
    Type retryOnExceptionType,
    Func &lt; T &gt; action,
    TimeSpan retryInterval =
    default (TimeSpan),
    int retryCount = 3) {
        if (retryInterval ==
        default (TimeSpan)) retryInterval = TimeSpan.FromSeconds(1);

        var exceptions = new List &lt; Exception &gt; ();

        for (int retry = 0; retry &lt; retryCount; retry++) {
            try {
                return action();
            } catch (Exception ex) {
                if (!retryOnExceptionType.IsInstanceOfType(ex)) throw;

                exceptions.Add(ex);
                Thread.Sleep(retryInterval);
            }
        }

        throw new AggregateException(exceptions);
    }
}
You should be able to wrap up your loops in a single method that takes a Func&lt;T&gt; and then do something like this:

public static T1 Do&lt;T1,T2,T3&gt;(Type retryOnExceptionType, Func&lt;T2,T3,T1&gt; action, T2 param1,
                              T3 param2, TimeSpan retryInterval, int retryCount)
{
    var del = new Func&lt;T1&gt;(() =&gt; action(param1, param2));
    return DoLoops&lt;T1&gt;(del, retryOnExceptionType, retryInterval, retryCount);
}


public static T Do&lt;T&gt;(Type retryOnExceptionType, Func&lt;T&gt; action,TimeSpan retryInterval,
                      int retryCount)
{
    return DoLoops&lt;T&gt;(action, retryOnExceptionType, retryInterval, retryCount);
}

private static T DoLoops&lt;T&gt;(Func&lt;T&gt; func, Type retryOnExceptionType,
                            TimeSpan retryInterval, int retryCount)
{
    if (retryInterval == default(TimeSpan))
        retryInterval = TimeSpan.FromSeconds(1);

    var exceptions = new List&lt;Exception&gt;();

    for (int retry = 0; retry &lt; retryCount; retry++)
    {
        try
        {
            return func();
        }
        catch (Exception ex)
        {
            if (!retryOnExceptionType.IsInstanceOfType(ex))
                throw;

            exceptions.Add(ex);
            Thread.Sleep(retryInterval);
        }
    }

    throw new AggregateException(exceptions);
}


The key is in wrapping up your Func&lt;T2, T3, T1&gt; call in a separate Func&lt;T1&gt;, which allows you to pass a parameterless delegate to DoLoops regardless of how many type parameters the original delegate has, since that's the only difference between the original methods.

Even simpler, you can do away with DoLoops and just keep the for loop in the public static T Do&lt;T&gt; overload and Do&lt;T1, T2, T3&gt; can just pass the parameterless delegate it creates into that method:

public static T1 Do&lt;T1,T2,T3&gt;(Type retryOnExceptionType, Func&lt;T2,T3,T1&gt; action, T2 param1,
                              T3 param2, TimeSpan retryInterval, int retryCount)
{
    return Do&lt;T1&gt;(retryOnExceptionType, () =&gt; action(param1, param2),
                  retryInterval, retryCount);
}


public static T Do&lt;T&gt;(Type retryOnExceptionType, Func&lt;T&gt; action, TimeSpan retryInterval,
                      int retryCount)
{
    if (retryInterval == default(TimeSpan))
        retryInterval = TimeSpan.FromSeconds(1);

    var exceptions = new List&lt;Exception&gt;();

    for (int retry = 0; retry &lt; retryCount; retry++)
    {
        try
        {
            return action();
        }
        catch (Exception ex)
        {
            if (!retryOnExceptionType.IsInstanceOfType(ex))
                throw;

            exceptions.Add(ex);
            Thread.Sleep(retryInterval);
        }
    }

    throw new AggregateException(exceptions);
}