我想创建一个完整的Task
(不是Task<T>
)。 .NET中是否有内置的东西可以做到这一点?
答案 0 :(得分:213)
newest version of .Net (v4.6)正在添加内置的Task.CompletedTask:
Task completedTask = Task.CompletedTask;
该属性是作为无锁单例实现的,因此您几乎总是使用相同的已完成任务。
答案 1 :(得分:142)
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;
}
答案 2 :(得分:57)
我这样做的首选方法是在没有参数的情况下调用Task.WhenAll()
。 MSDN documentation表示“如果提供的数组/可枚举不包含任务,则返回的任务将在返回给调用者之前立即转换到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()来公开的。
答案 3 :(得分:32)
我会使用Task.Delay(0)
。在内部,它返回已完成Task<T>
的缓存实例。这正是当前答案建议做的事情,只是现在你不必自己缓存一个实例,你的代码中也没有任何不优雅的垃圾值。
您可能认为可以使用Task.Yield()
,但事实证明Task.Yield()
的结果不是 Task
的子类型,而结果Task.Delay(0)
是。这是两者之间的微妙差异之一。
答案 4 :(得分:26)
您可以使用Task.FromResult(在.NET 4.5中)返回已完成的Task<T>
。
如果您需要非通用Task
,则可以始终使用Task.FromResult(0)
或类似内容,因为Task<T>
是Task
的子类。
答案 5 :(得分:7)
您可以使用来自Nito.AsyncEx.TaskConstants.Completed的优秀图书馆AsyncEx中的Stephen Cleary。
答案 6 :(得分:7)
对于.Net 4.6及以上版本使用
return Task.CompletedTask;
对于较低版本,您可以使用
return new Task(() => { });