Files
sbox-public/engine/Sandbox.System/Utility/ReflectionCache.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

59 lines
1.9 KiB
C#

using System.Collections;
using System.Collections.Concurrent;
using System.Reflection;
namespace Sandbox;
/// <summary>
/// Lazily performs expensive reflection, caching the result.
/// Clears itself during hotloads.
/// </summary>
internal sealed class ReflectionCache<TKey, TValue> : IHotloadManaged
where TKey : MemberInfo
{
[SkipHotload]
private readonly ConcurrentDictionary<TKey, TValue> _cache = new();
private readonly Func<TKey, TValue> _getValue;
private readonly KeyValuePair<TKey, TValue>[] _defaultItems;
/// <summary>
/// Creates a <see cref="ReflectionCache{TKey,TValue}"/>, wrapping a function to get a <typeparamref name="TValue"/>
/// lazily from a <typeparamref name="TKey"/>.
/// </summary>
/// <param name="getValue">Expensive reflection to lazily run once per <typeparamref name="TKey"/>.</param>
/// <param name="defaultItems">Items to initialize the cache with. Will be added again after each hotload.</param>
public ReflectionCache( Func<TKey, TValue> getValue, params KeyValuePair<TKey, TValue>[] defaultItems )
{
_getValue = getValue;
_defaultItems = defaultItems;
AddDefaultItems();
}
/// <summary>
/// Attempts to add the specified key and value to the <see cref="ReflectionCache{TKey,TValue}"/>.
/// </summary>
/// <returns><see langword="true"></see> if the item was added, <see langword="false"></see> if an item already had a matching key.</returns>
public bool TryAdd( TKey key, TValue value ) => _cache.TryAdd( key, value );
/// <summary>
/// Gets a cached value for the given <paramref name="key"/> if it exists, otherwise
/// runs the expensive function wrapped by this instance and stores it.
/// </summary>
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();
}
}