Pin Lu
Pin Lu

Reputation: 1

c# how to pass different functions to another function by using delegate

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

Answers (1)

HaroldHues
HaroldHues

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

Related Questions