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 usingObject
. Then, when theAction
is executed successfully,SetResult
is still used to transition theTask
into theRanToCompletion
final state; however, since the actual result value is irrelevant,null
is used. Finally,RunAsync
returnsTask
rather thanTask<Object>
. Of course, the instantiatedtask
’s type is stillTask<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).
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 await
s 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.