snippetcsharpMinor
How can I avoid repeated code using lambdas?
Viewed 0 times
lambdascanrepeatedavoidusinghowcode
Problem
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#?
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 (
retryOnExceptionType, () = > {
action();
return null;
}, retryInterval, retryCount);
}
public static T1 Do (
Type retryOnExceptionType,
Func action,
T2 param1,
T3 param2,
TimeSpan retryInterval =
default (TimeSpan),
int retryCount = 3) {
if (retryInterval ==
default (TimeSpan)) retryInterval = TimeSpan.FromSeconds(1);
var exceptions = new List ();
for (int retry = 0; retry (
Type retryOnExceptionType,
Func action,
TimeSpan retryInterval =
default (TimeSpan),
int retryCount = 3) {
if (retryInterval ==
default (TimeSpan)) retryInterval = TimeSpan.FromSeconds(1);
var exceptions = new List ();
for (int retry = 0; retry < retryCount; retry++) {
try {
return action();
} catch (Exception ex) {
if (!retryOnExceptionType.IsInstanceOfType(ex)) throw;
exceptions.Add(ex);
Thread.Sleep(retryInterval);
}
}
throw new AggregateException(exceptions);
}
}Solution
You should be able to wrap up your loops in a single method that takes a
The key is in wrapping up your
Even simpler, you can do away with
Func and then do something like this:public static T1 Do(Type retryOnExceptionType, Func action, T2 param1,
T3 param2, TimeSpan retryInterval, int retryCount)
{
var del = new Func(() => action(param1, param2));
return DoLoops(del, retryOnExceptionType, retryInterval, retryCount);
}
public static T Do(Type retryOnExceptionType, Func action,TimeSpan retryInterval,
int retryCount)
{
return DoLoops(action, retryOnExceptionType, retryInterval, retryCount);
}
private static T DoLoops(Func func, Type retryOnExceptionType,
TimeSpan retryInterval, int retryCount)
{
if (retryInterval == default(TimeSpan))
retryInterval = TimeSpan.FromSeconds(1);
var exceptions = new List();
for (int retry = 0; retry < 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 call in a separate Func, 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 overload and Do can just pass the parameterless delegate it creates into that method:public static T1 Do(Type retryOnExceptionType, Func action, T2 param1,
T3 param2, TimeSpan retryInterval, int retryCount)
{
return Do(retryOnExceptionType, () => action(param1, param2),
retryInterval, retryCount);
}
public static T Do(Type retryOnExceptionType, Func action, TimeSpan retryInterval,
int retryCount)
{
if (retryInterval == default(TimeSpan))
retryInterval = TimeSpan.FromSeconds(1);
var exceptions = new List();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
return action();
}
catch (Exception ex)
{
if (!retryOnExceptionType.IsInstanceOfType(ex))
throw;
exceptions.Add(ex);
Thread.Sleep(retryInterval);
}
}
throw new AggregateException(exceptions);
}Code Snippets
public static T1 Do<T1,T2,T3>(Type retryOnExceptionType, Func<T2,T3,T1> action, T2 param1,
T3 param2, TimeSpan retryInterval, int retryCount)
{
var del = new Func<T1>(() => action(param1, param2));
return DoLoops<T1>(del, retryOnExceptionType, retryInterval, retryCount);
}
public static T Do<T>(Type retryOnExceptionType, Func<T> action,TimeSpan retryInterval,
int retryCount)
{
return DoLoops<T>(action, retryOnExceptionType, retryInterval, retryCount);
}
private static T DoLoops<T>(Func<T> func, Type retryOnExceptionType,
TimeSpan retryInterval, int retryCount)
{
if (retryInterval == default(TimeSpan))
retryInterval = TimeSpan.FromSeconds(1);
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
return func();
}
catch (Exception ex)
{
if (!retryOnExceptionType.IsInstanceOfType(ex))
throw;
exceptions.Add(ex);
Thread.Sleep(retryInterval);
}
}
throw new AggregateException(exceptions);
}public static T1 Do<T1,T2,T3>(Type retryOnExceptionType, Func<T2,T3,T1> action, T2 param1,
T3 param2, TimeSpan retryInterval, int retryCount)
{
return Do<T1>(retryOnExceptionType, () => action(param1, param2),
retryInterval, retryCount);
}
public static T Do<T>(Type retryOnExceptionType, Func<T> action, TimeSpan retryInterval,
int retryCount)
{
if (retryInterval == default(TimeSpan))
retryInterval = TimeSpan.FromSeconds(1);
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
return action();
}
catch (Exception ex)
{
if (!retryOnExceptionType.IsInstanceOfType(ex))
throw;
exceptions.Add(ex);
Thread.Sleep(retryInterval);
}
}
throw new AggregateException(exceptions);
}Context
StackExchange Code Review Q#67716, answer score: 6
Revisions (0)
No revisions yet.