创建一个已完成的任务

233
我想创建一个已完成的Task(不是 Task<T>)。.NET中是否有内置的方法可以实现这一点?
相关问题: 创建已完成的 Task<T>

2
似乎每个人都认为使用这样的垃圾值是正确的方法。没有其他方法可以避免使用垃圾值,这令人失望,但没办法。你认为这有什么问题吗?如果你缓存一个单独的“Task”,那么整个程序将占用额外的一位内存。这微不足道。此外,人们可以创建一个已完成的任务而不必这样做,只是没有任何改进。 - Servy
11
我的失望与需要使用额外的内存无关,只是因为代码中出现垃圾值不够优雅。 - Timothy Shields
1
请注意,现在有ValueTask用于已完成的任务(即对于您已经拥有的值,使代码本质上是同步的),这将节省您的分配。 - nawfal
8个回答

280

1
刚刚检查了最新的VS 14 CTP并创建了一个4.5.3项目,Task.CompletedTask仍然是内部的。 - Peter Ritchie
1
你要么没有下载最新的CTP(即4版,从该网站链接),要么没有指定4.5.3版本。这是我机器上的情况。@PeterRitchie - i3arnon
我在Azure上从Visual Studio 14镜像创建了一个虚拟机。 - Peter Ritchie
1
@PeterRitchie 来自Azure VS14CTP4模板 - i3arnon
我正在使用mono 5.4.1.7在Mac OS X上工作,我遇到了相同的错误。我该如何修复它? - Khaled Annajar

176

Task<T>可以隐式转换为Task,所以只需获取已完成的Task<T>(任何T和任何值)并使用它。您可以像这样使用它来隐藏实际结果的存在。

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

请注意,由于我们没有公开结果,并且任务始终已完成,因此我们可以缓存单个任务并重复使用它。
如果您正在使用.NET 4.0并且没有“FromResult”,则可以使用“TaskCompletionSource”创建自己的“FromResult”。
public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

9
如果你使用的是4.0版本,你可以添加Microsoft.Bcl.Async库以获得TaskEx.FromResult,以及其他方便的功能,比如WhenAll。 - Carl
@Servy FromResult(false)和FromResult(true)有什么区别? - Francesco Bonizzi
3
如果你关注结果,那么它会改变结果的布尔值。如果你忽略结果,那么结果是无关紧要的。 - Servy

71

我偏爱的方法是调用不带参数的Task.WhenAll()。根据MSDN文档:“如果提供的数组/可枚举对象不包含任何任务,则返回的任务将在返回给调用方之前立即转换为已完成状态。” 这听起来就像你想要的。

更新:我在Microsoft参考源中找到了源代码; 在那里,你可以看到Task.WhenAll包含以下内容:

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

因此,Task.CompletedTask确实是内部的,但通过调用WhenAll()而没有参数来公开它。


11
虽然它感觉有点狼狈,但是根据文档,它得到了支持,所以我不知道,我有点喜欢它! - sara
2
对于我和我的.NET 4.5.2受限代码来说,这已经足够优雅了。谢谢! - Stas Ivanov

39
我会使用Task.Delay(0)。在内部,它返回一个已完成的Task<T>实例的缓存副本。这正是当前答案建议做的事情,现在你不必自己缓存实例,也不会在代码中有任何不雅观的垃圾值。
您可能认为可以使用Task.Yield(),但是事实证明,Task.Yield()的结果不是Task的子类型,而Task.Delay(0)的结果则是。这是两者之间的微妙差异之一。

36

您可以在.NET 4.5中使用Task.FromResult返回已完成的Task<T>

如果您需要一个非泛型的Task,则始终可以使用Task.FromResult(0)或类似方法,因为Task<T>Task的子类。


15

对于 .Net 4.6 及以上版本,请使用

return Task.CompletedTask;

对于低版本,您可以使用

return new Task(() => { });

9
小心使用早期4.6版本的方法!你需要开始任务,否则它将永远不会完成!试试使用return Task.Delay(0);代替怎么样? - Miquel

8

Nito.AsyncEx.TaskConstants.Completed源代码文件链接已失效。 - harlam357
@harlam357 已修复。 - some_engineer

0

这样怎么样:

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

如果你不介意的话,可以省略警告抑制。


我认为即使您不使用它,将方法标记为“async”仍会创建整个状态机装置,因此对于低资源场景,返回一个空任务更有效率。 - Calvin Fisher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接