using System.Collections.Concurrent;
using System.Threading.Tasks;
private static readonly ConcurrentDictionary<string, string> ConcurrentDictionary = new ConcurrentDictionary<string, string>();
private static readonly LazyConcurrentDictionary<string, string> LazyConcurrentDictionary = new LazyConcurrentDictionary<string, string>();
public static void Main(string[] args)
var value = ConcurrentDictionary.GetOrAdd("key1", k => RunOnceMethod(k, nameof(ConcurrentDictionary)));
Console.WriteLine(value);
var value = LazyConcurrentDictionary.GetOrAdd("key2", k => RunOnceMethod(k, nameof(LazyConcurrentDictionary)));
Console.WriteLine(value);
private static string RunOnceMethod(string key, string caller)
Console.WriteLine($"[{caller}] I should only run once");
return $"{key}_{Guid.NewGuid()}";
public class LazyConcurrentDictionary<TKey, TValue>
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> concurrentDictionary;
public LazyConcurrentDictionary()
this.concurrentDictionary = new ConcurrentDictionary<TKey, Lazy<TValue>>();
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
var lazyResult = this.concurrentDictionary.GetOrAdd(key, k => new Lazy<TValue>(() => valueFactory(k), LazyThreadSafetyMode.ExecutionAndPublication));