是否可以提取MemoryCache
对象的内容,包括:
- 缓存项键
- 缓存项值
- 缓存项过期时间?
提取缓存项键和值很容易,并且在Internet上的其他地方有介绍。经过一些研究,似乎有一种方法来提取过期时间为每个项目。我们必须使用反射,因为框架不公开MemoryCache
的内部对象。
我们首先创建一个类来存储每个缓存项的信息:
public class MemoryCacheItemInfo
{
public string Key { get; private set; }
public object CacheItemValue { get; private set; }
public DateTime Created { get; private set; }
public DateTime LastUpdateUsage { get; private set; }
public DateTime AbsoluteExpiry { get; private set; }
public TimeSpan SlidingExpiry { get; private set; }
public MemoryCacheItemInfo(string key, object cacheItemValue,
DateTime created, DateTime lastUpdateUsage, DateTime absoluteExpiry,
TimeSpan slidingExpiry)
{
this.Key = key;
this.CacheItemValue = cacheItemValue;
this.Created = created;
this.LastUpdateUsage = lastUpdateUsage;
this.AbsoluteExpiry = absoluteExpiry;
this.SlidingExpiry = slidingExpiry;
}
}
现在,我们将使用反射访问私有MemoryCache
字段:
public static MemoryCacheItemInfo[] GetCacheItemInfo(this MemoryCache cache)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
FieldInfo field = typeof (MemoryCache).GetField("_stores", bindFlags);
object[] cacheStores = (object[]) field.GetValue(cache);
List<MemoryCacheItemInfo> info = new List<MemoryCacheItemInfo>();
foreach (object cacheStore in cacheStores)
{
Type cacheStoreType = cacheStore.GetType();
FieldInfo lockField = cacheStoreType.GetField("_entriesLock", bindFlags);
object lockObj = lockField.GetValue(cacheStore);
lock (lockObj)
{
FieldInfo entriesField = cacheStoreType.GetField("_entries", bindFlags);
Hashtable entriesCollection = (Hashtable) entriesField.GetValue(cacheStore);
foreach (DictionaryEntry cacheItemEntry in entriesCollection)
{
Type cacheItemValueType = cacheItemEntry.Value.GetType();
string key = (string) cacheItemEntry.Key.GetType().GetProperty("Key", bindFlags).GetValue(cacheItemEntry.Key);
PropertyInfo value = cacheItemValueType.GetProperty("Value", bindFlags);
PropertyInfo utcCreated = cacheItemValueType.GetProperty("UtcCreated", bindFlags);
PropertyInfo utcLastUpdateUsage = cacheItemValueType.GetProperty("UtcLastUpdateUsage", bindFlags);
PropertyInfo utcAbsoluteExpiry = cacheItemValueType.GetProperty("UtcAbsExp", bindFlags);
PropertyInfo utcSlidingExpiry = cacheItemValueType.GetProperty("SlidingExp", bindFlags);
MemoryCacheItemInfo mcii = new MemoryCacheItemInfo(
key,
value.GetValue(cacheItemEntry.Value),
((DateTime) utcCreated.GetValue(cacheItemEntry.Value)).ToLocalTime(),
((DateTime) utcLastUpdateUsage.GetValue(cacheItemEntry.Value)).ToLocalTime(),
((DateTime) utcAbsoluteExpiry.GetValue(cacheItemEntry.Value)).ToLocalTime(),
((TimeSpan) utcSlidingExpiry.GetValue(cacheItemEntry.Value))
);
info.Add(mcii);
}
}
}
return info.ToArray();
}
这种方法效率不高,不建议用于生产环境。
另外,访问MemoryCache
私有字段是不被Microsoft官方支持的。
MemoryCache
对象的内部结构可能会在将来发生变化,这会破坏此代码。