构建基于任务的连结符
因为任务可以完全代表异步操作、提供同步和异步功能来加入操作、检索其结果等,所以可以构建组成任务的连结符的库以构建更大的模式。 如前一部分所述,.NET 包括一些内置连结符,但是,你也可以构建自己的连结符。 以下各节提供了一些潜在的连结符方法和类型的示例。
RetryOnFault
在许多情况下,如果上次尝试失败,你可能想要重试操作。 对于同步代码,你可能会构建一个帮助器方法来实现此目的,如下例中的 RetryOnFault
:
C#
public static T RetryOnFault<T>(
Func<T> function, int maxTries)
{
for(int i=0; i<maxTries; i++)
{
try { return function(); }
catch { if (i == maxTries-1) throw; }
}
return default(T);
}
你可以为异步操作(使用 TAP 实现,因此返回任务)构建几乎相同的帮助器方法:
C#
public static async Task<T> RetryOnFault<T>(
Func<Task<T>> function, int maxTries)
{
for(int i=0; i<maxTries; i++)
{
try { return await function().ConfigureAwait(false); }
catch { if (i == maxTries-1) throw; }
}
return default(T);
}
然后,可以使用此连结符将重试编码到应用程序的逻辑中,例如:
C#
// Download the URL, trying up to three times in case of failure
string pageContents = await RetryOnFault(
() => DownloadStringAsync(url), 3);
可以进一步扩展 RetryOnFault
函数。 例如,该函数可以接受另一个 Func<Task>
(在重试间隔期间调用以确定何时重试该操作):
C#
public static async Task<T> RetryOnFault<T>(
Func<Task<T>> function, int maxTries, Func<Task> retryWhen)
{
for(int i=0; i<maxTries; i++)
{
try { return await function().ConfigureAwait(false); }
catch { if (i == maxTries-1) throw; }
await retryWhen().ConfigureAwait(false);
}
return default(T);
}
重试该操作前,可以使用以下函数等待片刻:
C#
// Download the URL, trying up to three times in case of failure,
// and delaying for a second between retries
string pageContents = await RetryOnFault(
() => DownloadStringAsync(url), 3, () => Task.Delay(1000));