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
Tis, I’ve defaulted to usingObject. Then, when theActionis executed successfully,SetResultis still used to transition theTaskinto theRanToCompletionfinal state; however, since the actual result value is irrelevant,nullis used. Finally,RunAsyncreturnsTaskrather 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
TaskCompletionSourceand 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 aTask<object>, The caller justawaits 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 fromTaskIt's also common to find a
Task<bool>that returns false, orTask<int>with 0.