When should TaskCompletionSource<T> be used?

Royi Namir picture Royi Namir · Mar 9, 2013 · Viewed 92.5k times · Source

AFAIK, all it knows is that at some point, its SetResult or SetException method is being called to complete the Task<T> exposed through its Task property.

In other words, it acts as the producer for a Task<TResult> and its completion.

I saw here the example:

If I need a way to execute a Func asynchronously and have a Task to represent that operation.

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

Which could be used *if I didn’t have Task.Factory.StartNew - But I do have Task.Factory.StartNew.

Question:

Can someone please explain by example a scenario related directly to TaskCompletionSource and not to a hypothetical situation in which I don't have Task.Factory.StartNew?

Answer

GameScripting picture GameScripting · Mar 9, 2013

I mostly use it when only an event based API is available (for example Windows Phone 8 sockets):

public Task<Args> SomeApiWrapper()
{
    TaskCompletionSource<Args> tcs = new TaskCompletionSource<Args>(); 

    var obj = new SomeApi();

    // will get raised, when the work is done
    obj.Done += (args) => 
    {
        // this will notify the caller 
        // of the SomeApiWrapper that 
        // the task just completed
        tcs.SetResult(args);
    }

    // start the work
    obj.Do();

    return tcs.Task;
}

So it's especially useful when used together with the C#5 async keyword.