我正在编写一些异步辅助方法,我有API支持Task
和Task<T>
。要重新使用代码,我希望基于Task
的API将给定任务包装为Task<T>
,并且只需调用Task<T>
API。
我能做到这一点的一种方法是:
private static async Task<bool> Convert(this Task @this)
{
await @this.ConfigureAwait(false);
return false;
}
然而,我想知道:有没有更好/内置的方法来做到这一点?
答案 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
不幸被包裹