此代码是否应返回任务或任务<object>?</object>

时间:2014-07-29 15:59:38

标签: c# .net task-parallel-library task taskcompletionsource

我正在阅读The Nature of 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后,仍会使用SetResultTask转换为RanToCompletion最终状态;但是,由于实际结果值无关紧要,因此使用null最后,RunAsync返回Task而不是Task<Object> 。当然,实例化的task类型仍然是Task<Object>,但我们不需要这样引用它,并且此方法的使用者不需要关心这些实现细节。

我并不特别理解为什么该方法应该返回Task而不是Task<object>(这就是我强调粗体句子的原因)。我知道该方法设置为返回Task,但tcsTaskCompletionSource<Object>,而不是TaskCompletionSource(我认为这是错误的。)

4 个答案:

答案 0 :(得分:4)

没有非通用的TaskCompletionSource,并且考虑到你想要的只是一个没有结果的任务,结果并不重要。 在这种情况下,调用者不知道也不关心任务实际上是Task<object>,调用者只是await,并且如果有,则获得异常。来电者不知道实际结果。

Task<T>继承自Task

这一事实促进了这一点

通常会找到返回false的Task<bool>,或者Task<int>返回0。

答案 1 :(得分:4)

没有用于创建TaskCompletionSource实例的非通用Task类,这些实例不是Task<T>的实例。当您不关心(或未提供)返回值时,这为TaskCompletionSource<T>的泛型类型参数留下了两个选项:

  1. 使用任意现有类型(例如object)作为返回类型。将值设置为null以指示任务完成。
  2. 使用特定的非公开类型,并将值设置为null以表示任务已完成。
  3. 当我创建TaskCompletionSource<T>实例以提供没有返回值的Task时,我更喜欢使用专用的非公共类型来确保使用代码不会错误返回Task 1}}作为结果具有意义的Task<T>的实例。

    首先,我定义了以下类(如果它嵌套在另一个类型中,它可以是private sealed class):

    internal sealed class VoidResult
    {
    }
    

    然后,我使用TaskCompletionSource<object>而不是使用TaskCompletionSource<VoidResult>作为完成源。由于调用代码无法访问VoidResult类型,因此用户将无法将Task对象强制转换为Task<VoidResult>的实例。

答案 2 :(得分:2)

  

我并不特别理解为什么该方法应该返回Task而不是Task<object>

因为当您返回Task<Object>时,这意味着当此方法完成时,它将生成一些类型Object的有用值。在这种情况下,我们不会产生任何结果,这就是为什么斯蒂芬选择返回Task

如果我们正在处理Func<Object>,那么返回Task<Object>是合适的,因为Func会产生一些结果,我们可能会选择退回。

  

为什么TaskCompletionSource<Object>,而不是TaskCompletionSource

因为没有这样的事情。没有非通用的TaskCompletionSource

答案 3 :(得分:1)

如果您返回了Task<object>,则var result = await RunAsync(...)将始终返回null,因为这是您将结果设置为的内容。

客户并不关心这一点,因此您只需返回Task

理想情况下,您可以在内部使用TaskCompletionSource,而不是使用TaskCompletionSource<object>,只需拨打SetCompleted()而不是SetResult(null)。但这种类型不存在。