Асинхронно ждать завершения Task с таймаутом

В целом необходимо одобрить интерфейсы по абстрактным классам. Одна причина использовать абстрактный класс состоит в том, если у Вас есть общая реализация среди реальных классов. Конечно, необходимо все еще объявить интерфейс (IPet) и иметь абстрактный класс (PetBase) реализация тот интерфейс. Используя маленькие, отличные интерфейсы, можно использовать кратные числа для дальнейшего улучшения гибкости. Интерфейсы позволяют максимальное количество гибкости и мобильность типов через границы. Когда передающие ссылки через границы, всегда передавайте интерфейс а не конкретный тип. Это позволяет принимающему концу определять конкретную реализацию и обеспечивает максимальную гибкость. Это абсолютно верно при программировании способом TDD/BDD.

Банда Четырех указанных в их книге, "Поскольку наследование представляет подкласс деталям реализации его родителя, часто говорится, что 'наследование повреждает инкапсуляцию". Я полагаю, что это верно.

347
задан dtb 22 November 2010 в 03:12
поделиться

2 ответа

Это - немного расширенная версия предыдущих ответов.

  • В дополнение к ответ Lawrence , это отменяет исходную задачу, когда тайм-аут происходит.
  • В addtion к варианты ответа sjb 2 и 3 , можно обеспечить CancellationToken для исходной задачи, и когда тайм-аут происходит, Вы добираетесь TimeoutException вместо OperationCanceledException.
async Task<TResult> CancelAfterAsync<TResult>(Func<CancellationToken, Task<TResult>> startTask, TimeSpan timeout, CancellationToken cancellationToken)
{
    using (var timeoutCancellation = new CancellationTokenSource())
    using (var combinedCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellation.Token))
    {
        var originalTask = startTask(combinedCancellation.Token);
        var delayTask = Task.Delay(timeout, timeoutCancellation.Token);
        var completedTask = await Task.WhenAny(originalTask, delayTask);
        // Cancel timeout to stop either task:
        // - Either the original task completed, so we need to cancel the delay task.
        // - Or the timeout expired, so we need to cancel the original task.
        // Canceling will not affect a task, that is already completed.
        timeoutCancellation.Cancel();
        if (completedTask == originalTask)
        {
            // original task completed
            return await originalTask;
        }
        else
        {
            // timeout
            throw new TimeoutException();
        }
    }
}
2
ответ дан 23 November 2019 в 00:28
поделиться

Я - recombinging идеи некоторых других ответов здесь и этот ответ на другом потоке в метод расширения стиля Попытки. Это обладает преимуществом, если Вы хотите дополнительный метод, уже избегая исключения на тайм-аут.

public static async Task<bool> TryWithTimeoutAfter<TResult>(this Task<TResult> task,
    TimeSpan timeout, Action<TResult> successor)
{

    using var timeoutCancellationTokenSource = new CancellationTokenSource();
    var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token))
                                  .ConfigureAwait(continueOnCapturedContext: false);

    if (completedTask == task)
    {
        timeoutCancellationTokenSource.Cancel();

        // propagate exception rather than AggregateException, if calling task.Result.
        var result = await task.ConfigureAwait(continueOnCapturedContext: false);
        successor(result);
        return true;
    }
    else return false;        
}     

async Task Example(Task<string> task)
{
    string result = null;
    if (await task.TryWithTimeoutAfter(TimeSpan.FromSeconds(1), r => result = r))
    {
        Console.WriteLine(result);
    }
}    
-1
ответ дан 23 November 2019 в 00:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: