Как условно запускать код асинхронно с помощью задач

У меня есть класс, отвечающий за извлечение ресурсов, который также кэширует их для быстрого доступа. Класс предоставляет асинхронный метод для извлечения ресурса:

public Task<object> GetResourceAsync(string resourceName)
{
    return Task.Factory.StartNew<object>(() =>
    {
        // look in cache

        // if not found, get from disk

        // return resource
    });
}

Затем код клиента выглядит следующим образом:

myResourceProvider.GetResourceAsync("myResource")
    .ContinueWith<object>(t => Console.WriteLine("Got resource " + t.Result.ToString()));

Таким образом, всегда используется фоновый поток. Однако я не хочу, чтобы код выполнялся асинхронно, если объект был найден в кеше. Если он был найден в кеше, я хотел бы немедленно вернуть ресурс и не использовать другой поток.

Спасибо.

Ответ 1

.NET 4.5 имеет Task.FromResult, который позволяет вернуть Task<T>, но вместо запуска делегата в потоке threadpool он явно устанавливает задачу возврата значение.

Итак, в контексте вашего кода:

public Task<object> AsyncGetResource(string resourceName)
{
    object valueFromCache;
    if (_myCache.TryGetValue(resourceName, out valueFromCache)) {
        return Task.FromResult(valueFromCache);
    }
    return Task.Factory.StartNew<object>(() =>
    {
        // get from disk
        // add to cache
        // return resource
    });
}

Если вы все еще используете .NET 4.0, вы можете использовать TaskCompletionSource<T>, чтобы сделать то же самое:

var tcs = new TaskCompletionSource<object>();
tcs.SetResult(...item from cache...);
return tcs.Task;