Reputation: 5696
Greetings!
I have a class which is used like a cache:
public sealed class MyCache<T> : IDisposable
{
private ReaderWriterLockSlim theLock = new ReaderWriterLockSlim();
private Dictionary<int, T> theCache = new Dictionary<int, T>();
public void Add(int key, T value)
{
// ... logic/code to add to the dictionary
}
public void Clear()
{
theLock.EnterWriteLock();
try
{
theCache.Clear();
}
finally
{
theLock.ExitWriteLock();
}
}
}
This cache is used many times, so there are often multiple instances of this at any given time.
Example 1:
public static class SpecialPageCache
{
public static MyCache<string> SpecialPage = new MyCache<string>();
}
Example 2:
public static class DdListCache
{
public static MyCache<List<int, string>> DdlList = new MyCache<List<int, string>>();
}
And so on.
I have a service that can clear the caches on-demand, but unfortunately, each one has to be cleared like so:
private void ClearThemAll()
{
SpecialPageCache.SpecialPage.Clear();
DdListCache.DdlList.Clear();
// repeat for all other caches that may exist ...
}
How can I use reflection (or something else?) to call each cache's Clear() method without having to explcitly do it for each one like I do in the above ClearThemAll() method?
Upvotes: 1
Views: 300
Reputation: 11548
If you really want to do reflection then you'd do something like this:
List<object> caches;
foreach (object obj in caches)
{
Type t = obj.GetType();
MethodInfo m = t.GetMethod("Clear");
// Object does not have a public instance method named "Clear"
if (m == null) { continue; }
m.Invoke(obj, new object[0]);
}
Upvotes: 0
Reputation: 1367
public interface ICache : IDisposable
{
void Clear();
}
public interface ICache<T> : ICache
{
}
public abstract class CacheBase<T> : ICache<T>
{
}
public sealed class SpecialPageCache : CacheBase<string>
{
internal SpecialPageCache()
{
}
}
public static class CacheFactory
{
private static List<ICache> cacheList = new List<ICache>();
public static TCache Create<TCache>()
where TCache : ICache, new()
{
var result = new TCache();
cacheList.Add(result);
return result;
}
public static void ClearAll()
{
cacheList.ForEach((c) => c.Clear());
}
}
Upvotes: 3
Reputation: 4004
This sound really familiar to how Inversion of Control containers work. Why not just have something like a
Dictionary<Type, Dictionary<int, object>>
All of the functions would then take a type T and then use that type to look up the appopriate dictionary. One static MyCache could handle all your type and it could be disposed with one call.
Upvotes: 0
Reputation: 2695
Why do you need to specifcally clear them are they using resources which need to be released ?
I'm wondering if you couldnt use the System.WeakReference so that the cache is garbarge collected as and when ?
http://msdn.microsoft.com/en-us/library/system.weakreference.aspx
Upvotes: 1
Reputation: 8084
Reflection sounds nasty. Without knowing more about your object lifetime, would the following work?
public abstract class MyCacheBase : IDisposable {
public static List<MyCache> caches = new List<MyCache>();
public MyCacheBase() {
caches.Add(this); // Add all constructed caches to the list
}
public static void ClearAllCaches() {
foreach (MyCache cache in cache) // clear all constructed
cache.Clear(); // caches in the list.
}
public void Finalize() {
Dispose();
}
public void Dispose() {
caches.Remove(this); // Remove disposed classes from the list
}
public abstract void Clear();
}
public sealed class MyCache<T> : MyCacheBase
{
// Rest of the implementation
}
(Thanks to Jon for noting the genericity. Almost missed it.)
If you want to have something like user specific caches you could add a user specific CacheFactory which would keep track of the caches created through it and its ClearAll() method would only clear those caches.
Upvotes: 1
Reputation: 1503200
Ick. You'd have to go through all the types in the assembly that you're interested in, and check all the static fields. This is made even more interesting because it's a generic type. Your life will be simpler if you have a nongeneric base class:
public abstract class MyCache : IDisposable
{
public abstract void Clear();
}
public sealed class MyCache<T> : MyCache
{
// ...
}
Then at least it's relatively easy to detect whether the type of a particular field is a MyCache
, fetch its value and call Clear
on it without messing around with reflection over generic types.
This is generally a nasty problem though - are you sure you want to clear all the caches like this, without really "understanding" which caches you're clearing?
Upvotes: 3
Reputation: 15578
You could store references to all of your instanced caches in a list. Then iterate same list, and call Clear on each MyCache. =)
Upvotes: 1