using System.Collections; using System.Collections.Concurrent; using System.Reflection; namespace Sandbox; /// /// Lazily performs expensive reflection, caching the result. /// Clears itself during hotloads. /// internal sealed class ReflectionCache : IHotloadManaged where TKey : MemberInfo { [SkipHotload] private readonly ConcurrentDictionary _cache = new(); private readonly Func _getValue; private readonly KeyValuePair[] _defaultItems; /// /// Creates a , wrapping a function to get a /// lazily from a . /// /// Expensive reflection to lazily run once per . /// Items to initialize the cache with. Will be added again after each hotload. public ReflectionCache( Func getValue, params KeyValuePair[] defaultItems ) { _getValue = getValue; _defaultItems = defaultItems; AddDefaultItems(); } /// /// Attempts to add the specified key and value to the . /// /// if the item was added, if an item already had a matching key. public bool TryAdd( TKey key, TValue value ) => _cache.TryAdd( key, value ); /// /// Gets a cached value for the given if it exists, otherwise /// runs the expensive function wrapped by this instance and stores it. /// public TValue this[TKey key] => _cache.GetOrAdd( key, _getValue ); private void AddDefaultItems() { foreach ( var item in _defaultItems ) { _cache.TryAdd( item.Key, item.Value ); } } void IHotloadManaged.Persisted() { _cache.Clear(); AddDefaultItems(); } }