创建完成的Task <T>


125

我正在实现一个方法,Task<Result> StartSomeTask()并且碰巧在调用该方法之前已经知道了结果。如何创建已经完成的Task <T>

这是我目前正在做的:

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var task = new Task<Result>(() => theResult);
    task.RunSynchronously(CurrentThreadTaskScheduler.CurrentThread);
    return task;
}

有更好的解决方案吗?


6
请注意,由于Task <T>继承自Task,因此此问题的答案也适用于创建普通Task(无<T>)。
Tim Lovell-Smith

注意,今天有ValueTask完成的任务(例如,您已经拥有的值,因此代码本质上是同步的),这将节省您的分配。
nawfal

Answers:


111
private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var taskSource = new TaskCompletionSource<Result>();
    taskSource.SetResult(theResult);
    return taskSource.Task;
}

@DanielLobo,如果您解释反对的话,您可能会得到答案
user2023861 '19

1
难道不是下面这样更简单,投票更多的人吗?@ user2023861
Daniel Lobo

203

定位.NET 4.5时,可以使用Task.FromResult

public static Task<TResult> FromResult<TResult>(TResult result);

要创建失败的任务,请使用Task.FromException

public static Task FromException(Exception exception);
public static Task<TResult> FromException<TResult>(Exception exception);

Task.CompletedTask如果需要非通用的.NET 4.6,则可以添加Task

public static Task CompletedTask { get; }

较旧版本的.NET的变通办法:

  • 当使用异步目标包(或AsyncCTP)定位.NET 4.0时,可以TaskEx.FromResult改用。

  • Task在.NET 4.6之前获得非泛型,可以使用Task<T>从或Task调用Task.FromResult<object>(null)或派生的事实Task.FromResult(0)


13
要返回非通用任务,最好使用Task.FromResult(0)之类的东西。使用“ null”作为参数可能会使无法确定通用参数的编译器感到困惑。
Whyllee

那例外呢?异步方法被编译到捕获异常的状态机中,并将其保存在返回的Task中。即使在第一次等待之前执行代码,也会发生这种情况。返回Task.FromResult的方法可能会直接引发异常。
罗伯特·瓦赞(RobertVažan)2013年

@RobertVažan一个有趣的边缘案例。可以说,如果您要从某个方法中检索已知结果,并且该方法引发异常,则存在需要修复的缺陷。
2014年

1
@RobertVažan您可以轻松地编写自己的FromException方法,其行为类似于FromResult但代表错误的任务。如果在结果任务中表示异常很重要,则这种方法可以简单地针对其错误情况返回该方法。
Servy

1
Task.FromException在.NET 4.5中不可用...我认为应该指定它。
STiLeTT

12

对于没有返回值的任务,.NET 4.6添加了Task.CompletedTask

它返回一个已经在TaskStatus.RanToCompletion中的任务。它可能每次都返回相同的实例,但是文档警告您不要依靠这个事实。



1

调用Task.WhenAll不带任何参数将返回已完成的任务。

Task task = Task.WhenAll();

虽然这会起作用,但它是一种晦涩的解决方法,可能会在阅读代码时使人们感到困惑,因为这意味着等待不存在的任务
Adrian Hristov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.