220

我想创建一个完整的Task(不是Task<T>)。.NET 中有内置的东西来做到这一点吗?

一个相关问题: 创建一个已完成的 Task<T>

4

8 回答 8

264

.Net (v4.6)的最新版本只是添加了一个内置的Task.CompletedTask

Task completedTask = Task.CompletedTask;

该属性被实现为无锁单例,因此您几乎总是使用相同的已完成任务。

于 2014-10-06T23:04:20.873 回答
169

Task<T>可以隐式转换为Task,因此只需获得一个已完成的Task<T>(具有任何T和任何值)并使用它。您可以使用类似的东西来隐藏实际结果在某处的事实。

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

请注意,由于我们没有公开结果,并且任务始终完成,我们可以缓存单个任务并重用它。

如果您使用的是 .NET 4.0 并且没有,FromResult那么您可以使用以下方法创建自己的TaskCompletionSource

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}
于 2013-01-09T18:44:07.393 回答
69

我首选的方法是Task.WhenAll()不带参数调用。MSDN 文档指出“如果提供的数组/可枚举不包含任务,则返回的任务将在返回给调用者之前立即转换为 RanToCompletion 状态。” 。这听起来像你想要的。

更新:我在Microsoft's Reference Source找到了源代码;在那里你可以看到 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() 来暴露的。

于 2014-11-04T14:32:18.127 回答
38

我会用Task.Delay(0). 在内部,它返回一个已完成的缓存实例Task<T>。无论如何,这正是当前答案建议做的事情,只是现在您不必自己缓存实例,代码中也没有任何不雅的垃圾值。

您可能认为您可以Task.Yield()改用,但事实证明 of 的结果Task.Yield()不是子类型Task,而 的结果Task.Delay(0)是。这是两者之间的细微差别之一。

于 2014-03-15T22:42:39.327 回答
34

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

如果你需要一个非泛型Task,你总是可以使用Task.FromResult(0)或类似的,因为Task<T>它是Task.

于 2013-01-09T18:42:06.933 回答
13

对于 .Net 4.6 及更高版本使用

return Task.CompletedTask;

对于较低版本,您可以使用

return new Task(() => { });
于 2017-03-08T11:47:42.883 回答
8

您可以使用来自Stephen Cleary的优秀库AsyncEx中的Nito.AsyncEx.TaskConstants.Completed

于 2014-10-29T16:05:24.567 回答
0

怎么样:

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

如果您不介意,可以忽略警告抑制。

于 2015-04-29T15:32:36.760 回答