首页 > 解决方案 > 具有可变输入的函数委托?

问题描述

我有一堆异步方法,它们都接受不同的输入,但它们都有相同的输出——一个名为HttpResponseData(例如)的类的实例。

现在我想调用一个同步方法RunWithRetry,它接受一个Func委托输入(并返回HttpResponseData)并运行它多次,直到某些条件变为真,如下面的示例代码:

public static async Task<HttpResponseData> RunWithRetry(Func<string, int, HttpResponseData> methodToRun,
    string input1, int input2, int maxRetryCount = 10, int retryIntervalDelayInMs = 5000)
{
    //some example usage code below where retry logic runs `methodToRun` as many times as needed

    HttpResponseData responseData = null;
    int triesDone = 0;

    while (triesDone <= maxRetryCount && (responseData == null || responseData.StatusCode != HttpStatusCode.OK))
    {
        if (triesDone > 0)
            Thread.Sleep(retryIntervalDelayInMs);

        responseData = await Task.FromResult(methodToRun(input1, input2));
        triesDone++;
    }
    return responseData;
}

问题是,Func<string, int, HttpResponseData> methodToRun定义为上面的输入需要输入参数的特定组合(在本例中:)string, int。这对我不起作用,因为正如我所说,我有许多不同的输入,它们都有不同的输入但输出相同:Task<HttpResponseData>. 所以我不想RunWithRetry用不同的输入集来指定这个方法的不同版本methodToRun

有没有办法可以定义Func具有特定输出但可变/不同输入的泛型?

标签: c#functional-programmingdelegatesfunc

解决方案


首先,我推荐使用 Polly,这是一个经过良好测试且广泛使用的重试逻辑库。

但是要回答您最初的问题,您真正想要做的是将参数“绑定”到您的委托,然后使用绑定的委托。因此,与其定义一个采用委托及其参数的方法,不如定义采用已经绑定到其参数的委托的方法。

像这样:

公共静态异步任务<HttpResponseData> RunWithRetry(Func<HttpResponseData> methodToRun,
    int maxRetryCount = 10, int retryIntervalDelayInMs = 5000)
{
    HttpResponseData 响应数据 = null;
    整数尝试完成 = 0;

    while (triesDone <= maxRetryCount && (responseData == null || responseData.StatusCode != HttpStatusCode.OK))
    {
        如果(尝试完成> 0)
            Thread.Sleep(retryIntervalDelayInMs);

        responseData = await Task.FromResult(methodToRun());
        尝试完成++;
    }
    返回响应数据;
}

用法更改为使用 lambda 表达式将“运行方法”方法与其参数绑定:

// 旧用法:
var response = await RunWithRetry(MethodToRun, "input1", 13, 10, 5000);

// 新用法:
var response = await RunWithRetry(() => MethodToRun("input1", 13), 10, 5000);

附带说明一下,await Task.FromResult是一种反模式。我认为这只是示例代码或不完整的代码。适当的异步“运行方法”将使用异步委托类型,如下所示:

公共静态异步任务<HttpResponseData> RunWithRetry(Func<Task<HttpResponseData>> methodToRun,
    int maxRetryCount = 10, int retryIntervalDelayInMs = 5000)
{
    HttpResponseData 响应数据 = null;
    整数尝试完成 = 0;

    while (triesDone <= maxRetryCount && (responseData == null || responseData.StatusCode != HttpStatusCode.OK))
    {
        如果(尝试完成> 0)
            Thread.Sleep(retryIntervalDelayInMs);

        responseData = 等待方法ToRun();
        尝试完成++;
    }
    返回响应数据;
}

// 用法:
var response = await RunWithRetry(() => MethodToRunAsync("input1", 13), 10, 5000);

推荐阅读