Reputation: 1
My problem is like this. I have several functions:
public List<FtpDirectoryEntry> ListDirectory();
public bool DirectoryExists(string dir);
public void UploadFile(string file);
public void UploadFiles(params string[] files);
I want to write a function to run these functions 5 times. If we can not get result in 5 times, it will throw exception.
public void CheckFunctionWithTrials( function X)
{
for (int i = 0; i < 5; i++)
{
try
{
X;
break;
}
catch (Exception e)
{
if (i == 5 - 1)
{
throw e;
}
else
{
DLog.Warn("Failed to upload file. Retry #" + (i + 1) + ": " + path);
Thread.Sleep(1000);
}
}
}
}
The problem is these function have different signature so I can not pass them as parameter using delegate. Is there a way or pattern can help me solve this problem?
Upvotes: 0
Views: 58
Reputation: 308
Note that this doesn't use delegates, but the Func<T>
and Action
types instead
I would change your signature to look like this:
public void CheckFunctionWithTrials(Action X)
This allows you to pass in a Function that takes no arguments and returns nothing. You could then call it with an anonymous function like so to "remove" the arguments.
CheckFunctionWithTrials(() => UploadFile(file));
This would make your complete function look something like this:
public void CheckFunctionWithTrials(Action X)
{
foreach (var i in Enumerable.Range(1, 5))
{
try
{
X?.Invoke();
break;
}
catch (Exception e)
{
if (i == 5)
{
throw;
}
else
{
//DLog.Warn("Failed to upload file. Retry #" + (i) + ": " + path);
Thread.Sleep(1000);
}
}
}
}
You also have return types on some of your functions, to get that to work you will need generics.
public T CheckFunctionWithTrials<T>(Func<T> X)
{
foreach (var i in Enumerable.Range(1, 5))
{
try
{
return X();
}
catch (Exception e)
{
if (i == 5)
{
throw;
}
else
{
//DLog.Warn("Failed to upload file. Retry #" + (i) + ": " + path);
Thread.Sleep(1000);
}
}
}
}
Where calling could look like this:
bool exists = CheckFunctionWithTrials(() => DirectoryExists(dir));
UPDATE:
I actually have a similar function in one of my local repos that retries a Task<T>
once. Same basic concept, just as an async
method
public async static Task<T> RetryOnceAsync<T>(this Func<Task<T>> tsk, TimeSpan wait)
{
try
{
return await tsk?.Invoke();
}
catch (Exception ex)
{
Logger.Error(ex.Message);
await Task.Delay(wait);
return await tsk?.Invoke();
}
}
Upvotes: 2