ClientCache
A cache for storing client instances, ensuring efficient reuse.
Implements an LRU eviction policy.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.ClientModel.Primitives
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class ClientCache
{
private readonly Dictionary<object, ClientEntry> _clients = new Dictionary<object, ClientEntry>();
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private readonly int _maxSize;
public ClientCache(int maxSize)
{
_maxSize = maxSize;
}
public T GetClient<T>(object clientId, Func<T> createClient) where T : class
{
_lock.EnterReadLock();
try {
if (_clients.TryGetValue(clientId, out ClientEntry value)) {
value.LastUsed = Stopwatch.GetTimestamp();
T val = value.Client as T;
if (val == null)
throw new InvalidOperationException($"""{value.Client.GetType()}""{typeof(T)}""");
return val;
}
} finally {
_lock.ExitReadLock();
}
_lock.EnterWriteLock();
try {
if (!_clients.TryGetValue(clientId, out ClientEntry value2)) {
T val2 = createClient();
_clients[clientId] = new ClientEntry(val2, Stopwatch.GetTimestamp());
if (_clients.Count > _maxSize)
Cleanup();
return val2;
}
value2.LastUsed = Stopwatch.GetTimestamp();
T val3 = value2.Client as T;
if (val3 == null)
throw new InvalidOperationException($"""{value2.Client.GetType()}""{typeof(T)}""");
return val3;
} finally {
_lock.ExitWriteLock();
}
}
private void Cleanup()
{
int num = _clients.Count - _maxSize;
if (num > 0) {
foreach (object item in (from kvp in (from kvp in _clients
orderby kvp.Value.LastUsed
select kvp).Take(num)
select kvp.Key).ToList()) {
if (_clients.TryGetValue(item, out ClientEntry value)) {
_clients.Remove(item);
(value.Client as IDisposable)?.Dispose();
}
}
}
}
}
}