Skip to content

Instantly share code, notes, and snippets.

@mvacha
Last active July 18, 2024 15:26
Show Gist options
  • Save mvacha/12bbe6da28c1d672926a51a2ad4c05ef to your computer and use it in GitHub Desktop.
Save mvacha/12bbe6da28c1d672926a51a2ad4c05ef to your computer and use it in GitHub Desktop.
Cached Tasks
// See https://aka.ms/new-console-template for more information
using System.Runtime.CompilerServices;
Console.WriteLine("Program started");
var cache = new Dictionary<string, object>();
//Use lambda, so the task does not start immediately
Func<Task<string>> taskFactory = async () =>
{
Console.WriteLine("Task started");
await Task.Delay(1000); // Simulate a delay
return "Task result";
};
//V1: use CachedTask class
var cachedTask = new CachedTask<string>("key", taskFactory, cache);
Console.WriteLine(await cachedTask);
//V2: use extension method
var cachedTask2 = taskFactory().Cached("key", cache);
Console.WriteLine(await cachedTask2);
public class CachedTask<T>(string key, Func<Task<T>> taskFactory, IDictionary<string, object> cache)
{
private readonly string _key = key;
private readonly Func<Task<T>> _taskFactory = taskFactory;
private readonly IDictionary<string, object> _cache = cache;
public async Task<T> GetValueAsync()
{
if (_cache.TryGetValue(_key, out object? value))
return (T)value;
var result = await _taskFactory().ConfigureAwait(false);
_cache[_key] = result;
return result;
}
//Make CachedTask awaitable
public TaskAwaiter<T> GetAwaiter() => GetValueAsync().GetAwaiter();
}
public static class TaskExtensions
{
public static Task<T> Cached<T>(this Task<T> task, string key, IDictionary<string, object> cache)
{
if (cache.TryGetValue(key, out object? value))
return Task.FromResult((T)value);
return task.ContinueWith(t =>
{
cache[key] = t.Result;
return t.Result;
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment