Полезные Расширения для Task<T>
Сегодня рассмотрим 5 полезных методов расширения для Task.
1. Запустил и забыл
Иногда нужно начать задачу и не ждать её завершения. Например, для некритических задач, когда не важен результат. Создадим метод расширения FireAndForget. При желании можно передать методу обработчик ошибок, который будет вызываться, когда задача выдаёт исключение:
public static void FireAndForget(Использование:
this Task task,
Action<Exception> errorHandler = null)
{
task.ContinueWith(t =>
{
if (t.IsFaulted && errorHandler != null)
errorHandler(t.Exception);
},
TaskContinuationOptions.OnlyOnFaulted);
}
SendEmailAsync().FireAndForget(2. Повтор
e => Console.WriteLine(e.Message));
Чтобы повторять задачу определённое количество раз, создадим метод расширения Retry. Он будет повторять задачу до тех пор, пока она не завершится успешно или не будет достигнуто максимальное количество попыток. Можно передать задержку между попытками:
public static async Task<TResult>Использование:
Retry<TResult>(
this Func<Task<TResult>> taskFactory,
int maxRetries,
TimeSpan delay)
{
for (int i = 0; i < maxRetries; i++)
{
try
{
return await taskFactory()
.ConfigureAwait(false);
}
catch
{
if (i == maxRetries - 1)
throw;
await Task.Delay(delay)
.ConfigureAwait(false);
}
}
// не должно достигать этого места
return default(TResult);
}
var result = await (3. Действие при сбое
() => GetResultAsync())
.Retry(3, TimeSpan.FromSeconds(1));
Выполняется при возникновении исключения в задаче:
public static async TaskИспользование:
OnFailure(this Task task,
Action<Exception> onFailure)
{
try
{
await task.ConfigureAwait(false);
}
catch (Exception ex)
{
onFailure(ex);
}
}
await GetResultAsync()4. Тайм-аут
.OnFailure(ex => Console.WriteLine(ex.Message));
Установка тайм-аута для задачи полезна, когда вы хотите, чтобы задача не выполнялась слишком долго (подойдёт, если задача не принимает токена отмены):
public static async TaskИспользование:
WithTimeout(this Task task,
TimeSpan timeout)
{
var delayTask = Task.Delay(timeout);
var completedTask = await
Task.WhenAny(task, delayTask)
.ConfigureAwait(false);
if (completedTask == delayTask)
throw new TimeoutException();
await task;
}
await GetResultAsync()Замечание: Начиная с .NET 6 для этой цели можно использовать WaitAsync.
.WithTimeout(TimeSpan.FromSeconds(1));
5. Результат по умолчанию
Иногда нужно вернуть результат по умолчанию при сбое задачи:
public static async Task<TResult>Использование:
Fallback<TResult>(
this Task<TResult> task,
TResult fallbackValue)
{
try
{
return await task.ConfigureAwait(false);
}
catch
{
return fallbackValue;
}
}
var result = await GetResultAsync()Источник: https://steven-giesel.com/blogPost/d38e70b4-6f36-41ff-8011-b0b0d1f54f6e
.Fallback("fallback");