将任务包装为任务<tresult> </tresult>的最佳方法是什么?

时间:2014-03-20 18:16:09

标签: c# task-parallel-library async-await

我正在编写一些异步辅助方法,我有API支持TaskTask<T>。要重新使用代码,我希望基于Task的API将给定任务包装为Task<T>,并且只需调用Task<T> API。

我能做到这一点的一种方法是:

private static async Task<bool> Convert(this Task @this)
{
    await @this.ConfigureAwait(false);
    return false;
}

然而,我想知道:有没有更好/内置的方法来做到这一点?

4 个答案:

答案 0 :(得分:6)

没有现成的Task方法可以做到这一点,没有。你的方法很好,很可能就像你能得到的一样简单。

使用任何其他方法实现正确的错误传播/取消语义看似很难。

答案 1 :(得分:5)

已更新,以下内容传播异常和取消:

public static class TaskExt
{
    public static Task<Empty> AsGeneric(this Task @this)
    {
        return @this.IsCompleted ?
            CompletedAsGeneric(@this) :
            @this.ContinueWith<Task<Empty>>(CompletedAsGeneric, 
                TaskContinuationOptions.ExecuteSynchronously).Unwrap();
    }

    static Task<Empty> CompletedAsGeneric(Task completedTask)
    {
        try
        {
            if (completedTask.Status != TaskStatus.RanToCompletion)
                // propagate exceptions
                completedTask.GetAwaiter().GetResult();

            // return completed task
            return Task.FromResult(Empty.Value);
        }
        catch (OperationCanceledException ex)
        {
            // propagate cancellation
            if (completedTask.IsCanceled)
                // return cancelled task
                return new Task<Empty>(() => Empty.Value, ex.CancellationToken);
            throw;
        }
    }
}

public struct Empty
{
    public static readonly Empty Value = default(Empty);
}

答案 2 :(得分:1)

最近我有相同的要求,我用自己的辅助程序扩展方法解决了该问题,该方法使用户可以用Task有效地包装Task<T>

public static async Task<TResult> WithCompletionResult<TResult>(
    this Task sourceTask,
    TResult result
)
{
    await sourceTask;
    return result;
}

在您的示例呼叫中,

Task<bool> task = myTask.WithCompletionResult<bool>(false);

如果Task<T>的结果无关紧要,我将使用:

Task<object> task = myTask.WithCompletionResult<object>(null);

我希望这会有所帮助。如果有人知道这种方法的陷阱,请告诉我!

答案 3 :(得分:-1)

使用await似乎有点矫枉过正。这里不需要状态机,只需使用ContinueWith

private static Task<bool> Convert(this Task @this)
{
    return @this.ContinueWith(p => { p.Wait(); return false;});
}

注意:这将导致AggregateException不幸被包裹