<PackageReference Include="Castle.Core" Version="4.1.0" />

SingletonDispenser<TKey, TItem>

public class SingletonDispenser<TKey, TItem>
using Castle.Core.Internal; using System; using System.Collections.Generic; using System.Threading; namespace Castle.Components.DictionaryAdapter.Xml { public class SingletonDispenser<TKey, TItem> where TItem : class { private readonly Castle.Core.Internal.Lock locker; private readonly Dictionary<TKey, object> items; private readonly Func<TKey, TItem> factory; public TItem this[TKey key] { get { return GetOrCreate(key); } protected set { items[key] = value; } } public SingletonDispenser(Func<TKey, TItem> factory) { if (factory == null) throw Error.ArgumentNull("factory"); locker = new SlimReadWriteLock(); items = new Dictionary<TKey, object>(); this.factory = factory; } private TItem GetOrCreate(TKey key) { if (!TryGetExistingItem(key, out object item)) return Create(key, item); return (item as TItem) ?? WaitForCreate(key, item); } private bool TryGetExistingItem(TKey key, out object item) { using (locker.ForReading()) { if (items.TryGetValue(key, out item)) return true; } using (IUpgradeableLockHolder upgradeableLockHolder = locker.ForReadingUpgradeable()) { if (items.TryGetValue(key, out item)) return true; using (upgradeableLockHolder.Upgrade()) items[key] = (item = new ManualResetEvent(false)); } return false; } private TItem WaitForCreate(TKey key, object item) { ((ManualResetEvent)item).WaitOne(); using (locker.ForReading()) return (TItem)items[key]; } private TItem Create(TKey key, object item) { ManualResetEvent manualResetEvent = (ManualResetEvent)item; TItem val = factory(key); using (locker.ForWriting()) items[key] = val; manualResetEvent.Set(); return val; } } }