Skip to content

Commit 380a857

Browse files
committed
Support externally managed reflection caches.
1 parent f940591 commit 380a857

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

src/Autofac/Core/ReflectionCacheSet.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public sealed class ReflectionCacheSet
1818

1919
private readonly ConcurrentDictionary<string, IReflectionCache> _caches = new();
2020

21+
private readonly List<WeakReference<IReflectionCache>> _externalCaches = new();
22+
2123
/// <summary>
2224
/// Initializes a new instance of the <see cref="ReflectionCacheSet"/> class.
2325
/// </summary>
@@ -101,6 +103,26 @@ public TCacheStore GetOrCreateCache<TCacheStore>(string cacheName, Func<string,
101103
}
102104
}
103105

106+
/// <summary>
107+
/// Register an externally-owned <see cref="IReflectionCache"/> so it participates
108+
/// in <see cref="Clear()"/> and <see cref="Clear(ReflectionCacheClearPredicate)"/> calls.
109+
/// The cache is held via a weak reference so it does not prevent garbage collection
110+
/// of the owning object (e.g., a container or registration source).
111+
/// </summary>
112+
/// <param name="cache">The cache to register.</param>
113+
public void RegisterExternalCache(IReflectionCache cache)
114+
{
115+
if (cache is null)
116+
{
117+
throw new ArgumentNullException(nameof(cache));
118+
}
119+
120+
lock (_externalCaches)
121+
{
122+
_externalCaches.Add(new WeakReference<IReflectionCache>(cache));
123+
}
124+
}
125+
104126
/// <summary>
105127
/// Clear the internal reflection cache. Only call this method if you are
106128
/// dynamically unloading types from the process; calling this method
@@ -117,6 +139,8 @@ public void Clear()
117139
{
118140
cache.Clear();
119141
}
142+
143+
ClearExternalCaches(static cache => cache.Clear());
120144
}
121145

122146
/// <summary>
@@ -139,6 +163,8 @@ public void Clear(ReflectionCacheClearPredicate predicate)
139163
{
140164
cache.Clear(predicate);
141165
}
166+
167+
ClearExternalCaches(cache => cache.Clear(predicate));
142168
}
143169

144170
/// <summary>
@@ -173,6 +199,25 @@ private static bool TryGetSharedCache([NotNullWhen(true)] out ReflectionCacheSet
173199
return _sharedSet.TryGetTarget(out sharedCache);
174200
}
175201

202+
private void ClearExternalCaches(Action<IReflectionCache> clearAction)
203+
{
204+
lock (_externalCaches)
205+
{
206+
for (var i = _externalCaches.Count - 1; i >= 0; i--)
207+
{
208+
if (_externalCaches[i].TryGetTarget(out var cache))
209+
{
210+
clearAction(cache);
211+
}
212+
else
213+
{
214+
// Prune dead references.
215+
_externalCaches.RemoveAt(i);
216+
}
217+
}
218+
}
219+
}
220+
176221
private IEnumerable<IReflectionCache> GetAllCaches()
177222
{
178223
foreach (var externalItem in _caches)

0 commit comments

Comments
 (0)