c#如何使用委托将不同的函数传递给另一个函数

时间:2016-03-08 23:16:21

标签: c# delegates

我的问题是这样的。我有几个功能:

public List<FtpDirectoryEntry> ListDirectory();
public bool DirectoryExists(string dir);
public void UploadFile(string file);
public void UploadFiles(params string[] files);

我想编写一个函数来运行这些函数5次。如果我们无法获得5次结果,它将抛出异常。

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);
            }
        }
    }
}

问题是这些函数有不同的签名,所以我不能使用委托将它们作为参数传递。有没有办法或模式可以帮我解决这个问题?

1 个答案:

答案 0 :(得分:2)

请注意,这不使用委托,而是使用Func<T>Action类型

我会将您的签名更改为:

public void CheckFunctionWithTrials(Action X)

这允许您传入一个不带参数且不返回任何内容的函数。然后,您可以使用匿名函数调用它,以“删除”参数。

CheckFunctionWithTrials(() => UploadFile(file));

这将使您的完整功能看起来像这样:

    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);
                }
            }
        }
    }

你也有一些函数的返回类型,为了让它工作,你需要泛型。

    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);
                }
            }
        }
    }

调用可能如下所示:

bool exists = CheckFunctionWithTrials(() => DirectoryExists(dir));

UPDATE:我实际上在我的一个本地存储库中有一个类似的功能,它重试Task<T>一次。相同的基本概念,就像async方法

一样
    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();
        }
    }