Cold Tasks and TaskExtensions.Unwrap

.net-4.5, async-await, c#, c#-5.0, task-parallel-library

Solution

All you need to do is to keep the `Task` before unwrapping it around and start that:

public Task<TValue> GetOrAddAsync(TKey key, Func<Task<TValue>> taskFunc)
{
    Task<Task<TValue>> wrappedTask = new Task<Task<TValue>>(taskFunc);
    Task<TValue> unwrappedTask = wrappedTask.Unwrap();

    Task<TValue> cachedTask = base.GetOrAdd(key, unwrappedTask);

    if (cachedTask == unwrappedTask)
        wrappedTask.Start();

    return cachedTask;
}

Usage:

cache.GetOrAddAsync(
    "key", async () =>
    {
        var r = await AsyncOperation();
        return r.FastSynchronousTransform();
    });

Problem

I've got a caching class that uses cold (unstarted) tasks to avoid running the expensive thing multiple times. ``` public class AsyncConcurrentDictionary<TKey, TValue> : System.Collections.Concurrent.ConcurrentDictionary<TKey, Task<TValue>> { internal Task<TValue> GetOrAddAsync(TKey key, Task<TValue> newTask) { var cachedTask = base.GetOrAdd(key, newTask); if (cachedTask == newTask && cachedTask.Status == TaskStatus.Created) // We won! our task is now the cached task, so run it cachedTask.Start(); return cachedTask; } } ``` This works great right up until your task is actually implemented using C#5's `await`, ala ``` cache.GetOrAddAsync("key", new Task(async () => { var r = await AsyncOperation(); return r.FastSynchronousTransform(); }));)` ``` Now it looks like `TaskExtensions.Unwrap()` does exactly what I need by turning `Task<Task<T>>` into a `Task<T>`, but it seems that wrapper it returns doesn't actually support `Start()` - it throws an exception. `TaskCompletionSource` (my go to for slightly special Task needs) doesn't seem to have any facilities for this sort of thing either. Is there an alternative to `TaskExtensions.Unwrap()` that supports "cold tasks"?

Original source