如何在C#中使用委托参数泛化异步方法以减少冗余代码?

How to generalize async methods with delegate parameters in C# to reduce redundant code?

提问人:Samhain323 提问时间:11/17/2023 最后编辑:Theodor ZouliasSamhain323 更新时间:11/17/2023 访问量:89

问:

我有一些异步方法,我想尝试一定次数,直到它们返回 true 或达到最大尝试次数,中间有延迟。我已经能够得到我想要的结果,但无法减少冗余。

函数返回 。Task<bool>

下面的代码是我试图概括的(因为只有函数调用行不同)

for (int attempts = 0; attempts < numOfTaskAttempts; ++attempts)
{
    if (!await UpdateSingleUserStatistic(sendingPlayer, PlayfabServerKeys.DailyPuzzle, request.score))
        await Task.Delay(taskAttemptDelay);
    else
        break
}

我试图通过创建传递委托的方法(如下)来泛化,因为只有一行不同,但由于某种原因,看不到泛化它们的方法。

在搜索这个网站时,我首先尝试传递一个任务而不是一个委托,但这只运行了一次任务。

我编写了以下方法,其中 Func 的签名会发生变化,提供的字符串参数也会发生变化。我似乎找不到一种方法使它们更通用(即只有一个方法并传递任务和/或委托)。

private static async Task<bool> CallAsyncMethodWithRetries(
    Func<Task<bool>> callback, int maxAttempts = numOfTaskAttempts,
    int delay = taskAttemptDelay)
{
    int numOfTries = 0;

    while (!await callback() && ++numOfTries < maxAttempts)
        await Task.Delay(delay);

    return numOfTries < maxAttempts;
}

private static async Task<bool> CallAsyncMethodWithRetries(
    Func<string, Task<bool>> callback, string arg,
    int maxAttempts = numOfTaskAttempts, int delay = taskAttemptDelay)
{
    int numOfTries = 0;

    while (!await callback(arg) && ++numOfTries < maxAttempts)
        await Task.Delay(delay);

    return numOfTries < maxAttempts;
}

private static async Task<bool> CallAsyncMethodWithRetries(
    Func<string, string, Task<bool>> callback, string arg1, string arg2,
    int maxAttempts = numOfTaskAttempts, int delay = taskAttemptDelay)
{
    int numOfTries = 0;

    while (!await callback(arg1, arg2) && ++numOfTries < maxAttempts)
        await Task.Delay(delay);

    return numOfTries < maxAttempts;
}

它们是如何称呼的:

bool isSuccess = false;
if (await CallAsyncMethodWithRetries(CreateAndSetTopPuzzlePlayers))
    if (await CallAsyncMethodWithRetries(SetTitleData, PlayfabServerKeys.DailyPuzzle, dailyPuzzle))
        isSuccess = await CallAsyncMethodWithRetries(ResetLeaderboard, PlayfabServerKeys.DailyPuzzle);

任何减少冗余代码的方法都将不胜感激。我对异步编程还很陌生,所以解决方案可能就在我面前,我可能不知道。

C# 异步 泛型 任务

评论

0赞 Theodor Zoulias 11/17/2023
相关:功能<>参数数量未知

答:

3赞 Julio Di Egidio 11/17/2023 #1

有多种方法可以解决这个问题,包括,正如在对问题的评论中提到的,具有可变数量参数的代表,以及使用反射。

但是,在这些情况下,最干净且实际上更实用的方法是简单地将 as 参数作为参数,然后使用 lambda 表达式调用它,该表达式使用所需的参数关闭(作为闭包)实际方法调用,例如:CallAsyncMethodWithRetriesFunc<Task<bool>>

await CallAsyncMethodWithRetries(() => ResetLeaderboard(PlayfabServerKeys.DailyPuzzle));

这是一个完整的示例(稍微简化了您的代码,我删除了参数默认值): https://dotnetfiddle.net/JVKUYP

评论

0赞 Enigmativity 11/17/2023
需要明确的是,您是在建议 OP 的第一种方法是答案。
0赞 Julio Di Egidio 11/17/2023
虽然我的答案只是部分与 OP 的第一个片段相匹配,但这只是偶然的,OP 中没有答案,而是在考虑超载的签名:事实上,我给出了一个甚至没有受到关注的答案,事实上我已经解释了这个想法是什么以及它是如何工作的。
0赞 Enigmativity 11/17/2023
你说的“甚至在雷达下”是什么意思?你的意思是“甚至不在雷达上”吗?