Search code examples
c#.nettask-parallel-librarytasktaskcompletionsource

Should this code return a Task or Task<object>?


I was reading The Nature of TaskCompletionSource, a post by 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;
}

Since we no longer care what the type of T is, I’ve defaulted to using Object. Then, when the Action is executed successfully, SetResult is still used to transition the Task into the RanToCompletion final state; however, since the actual result value is irrelevant, null is used. Finally, RunAsync returns Task rather than Task<Object>. Of course, the instantiated task’s type is still Task<Object>, but we need not refer to it as such, and the consumer of this method need not care about those implementation details.

I don't particularly understand why the method should return Task rather than Task<object> (which is why I emphasised the bold sentence). I know the method is set to return Task but tcs is a TaskCompletionSource<Object>, not TaskCompletionSource (which is wrong, I think).


Solution

  • There isn't a non generic TaskCompletionSource and considering all you want is a task without a result, the result doesn't matter. The caller doesn't know and doesn't care in this case that the Task is actually a Task<object>, The caller just awaits it, and gets an exception if there is one. The caller is unaware of the actual result.

    This of course is facilitated by the fact that Task<T> inherits from Task


    It's also common to find a Task<bool> that returns false, or Task<int> with 0.