0

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?

3
  • How do you expect to call one of those functions if you don't even know what parameters they take? Commented Mar 8, 2016 at 23:31
  • @DavidG I know it does not work. But it can help me explain what I want to do. Commented Mar 9, 2016 at 22:37
  • It doesn't make any sense though. Even if you pass them in, what parameters would you give to them inside the CheckFunctionWithTrials method? Commented Mar 9, 2016 at 22:45

1 Answer 1

2

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();
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.