此代码应该返回 Task 还是 Task<object> 吗?
-
21-12-2019 - |
题
我正在读书 TaskCompletionSource 的本质, ,Stephen Toub 的帖子。
public static Task RunAsync(Action action)
{
var tcs = new TaskCompletionSource<Object>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
action();
tcs.SetResult(null);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
因为我们不再关心什么类型
T
是的,我默认使用Object
. 。然后,当Action
执行成功,SetResult
仍然用于过渡Task
进入RanToCompletion
最终状态;然而,由于实际结果值无关紧要,null
用来。 最后,RunAsync
回报Task
而不是Task<Object>
. 。当然,实例化的task
的类型仍然是Task<Object>
, ,但我们不需要这样引用它,并且该方法的使用者不需要关心那些实现细节。
我不是特别明白为什么该方法应该返回 Task
而不是 Task<object>
(这就是为什么我强调粗体句子)。我知道该方法设置为返回 Task
但 tcs
是一个 TaskCompletionSource<Object>
, , 不是 TaskCompletionSource
(我认为这是错误的)。
解决方案
没有非通用的 TaskCompletionSource
考虑到你想要的只是一项没有结果的任务,结果并不重要。在这种情况下,调用者不知道也不关心任务实际上是一个 Task<object>
, 调用者只需 await
是的,如果有的话就会得到一个例外。调用者不知道实际结果。
这当然是由以下事实促进的: Task<T>
继承自 Task
找到一个也很常见 Task<bool>
返回 false,或者 Task<int>
与 0。
其他提示
没有非通用的 TaskCompletionSource
用于创建实例的类 Task
哪些不是实例 Task<T>
. 。这为泛型类型参数留下了两个选项 TaskCompletionSource<T>
当您不关心(或不提供)返回值时:
- 使用任意现有类型,例如
object
, ,作为返回类型。将值设置为null
来表示任务完成。 - 使用特定的非公共类型,并将值设置为
null
来表示任务完成。
当我创建一个 TaskCompletionSource<T>
实例的目的是提供 Task
由于没有返回值,我更喜欢使用专用的非公共类型来确保使用代码不会错误地返回 Task
作为一个例子 Task<T>
结果有意义。
首先,我定义以下类(它可以是 private sealed class
如果它嵌套在另一种类型中):
internal sealed class VoidResult
{
}
然后,不要使用 TaskCompletionSource<object>
对于完成源,我使用 TaskCompletionSource<VoidResult>
. 。自从 VoidResult
类型无法通过调用代码访问,用户将无法强制转换 Task
对象的实例 Task<VoidResult>
.
我不是特别明白为什么该方法应该返回
Task
而不是Task<object>
因为当你回来时 Task<Object>
这意味着当这个方法完成时,它将产生一些有用的类型值 Object
. 。在这种情况下,我们不会产生任何结果,这就是斯蒂芬选择返回的原因 Task
.
如果我们正在处理 Func<Object>
然后返回 Task<Object>
是适当的,因为 Func
会产生一些结果,我们可以选择返回它。
为什么
TaskCompletionSource<Object>
, , 不是TaskCompletionSource
?
因为没有这样的事情。没有非通用的 TaskCompletionSource
.
如果您退回了 Task<object>
, , 然后 var result = await RunAsync(...)
总会回来 null
, ,因为这就是您要设置的结果。
客户并不关心这个,所以你只需返回一个 Task
.
理想情况下,您会使用 TaskCompletionSource
内部,而不是 TaskCompletionSource<object>
, ,然后调用类似的东西 SetCompleted()
代替 SetResult(null)
. 。但这种类型并不存在。