Search code examples
c#.net.net-4.0task-parallel-librarytaskcompletionsource

When should TaskCompletionSource<T> be used?


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<T> asynchronously and have a Task<T> 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?


Solution

  • 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.