第二节:从程序集的角度分析MemoryCache,并完成基本封装
一. 轻车熟路
有了上一个章节对 System.Web.Caching.Cache 的探究,这里我们按照同样的思路对 MemoryCache 进行探究,相信必定会得心应手。
1. 程序集准备
a. 需要给项目添加 System.Runtime.Cacheing程序集。
b. 需要给使用的地方添加两个引用。
2. 程序集探究
在对应的类中输入关键字 MemoryCache,选中点击F12,查看MemoryCache程序集,如下图所示:
细心的人会发现:MemoryCache继承了ObjectCache,那么我们在使用的时候,是不是可以考虑一下,里氏替换原则呢? 后面揭晓。
下面我们一起来分析从上往下来分析一下该程序集。
(1). 构造函数和属性。我们利用Default属性来代替 通过构造函数 new 来实例化对象。
(2). 其他特有的新增属性。
可用内存量、可用物理内存百分比、更新内存前等待的时间量。
(3). 顾名思义通俗易懂的方法。
a:Contains方法:根据key,来判断缓存是否存在。
b:Get方法:根据key,来获取对应类型的缓存,通常结合泛型来封装。
c: GetCount方法:获取缓存的个数。
d: Remove方法:移除指定key的缓存。
e:缓存的增加。
从程序集中可以看到,从长相貌似与增加相关的有:Add、AddOrGetExisting、Set,事实也是如此,这三类方法确实是与增加缓存相关的。
这样我们优先分析一下他们相同参数。
参数1: CacheItem item
查看CacheItem的源代码,发现实质上他就是把缓存的key和value转换成属性后的一个实体。
参数2:CacheItemPolicy policy
查看CacheItemPolicy的源代码,发现该实体实体实质上就是把缓存常用的一些参数进行了封装,包括:相对过期时间、绝对过期时间、优先级、缓存失效前的回调、缓存失效后的回调。
但注意:没有“缓存依赖”这个选项哦。
与System.Web.Caching.Cache 相比,相对过期时间和绝对过期时间的用法,用哪个,就设置哪个属性,另外一个忽略即可。
区分:
A:Add方法插入: 如果插入成功,则为 true;如果缓存中已存在具有与 item 相同的键的项,则为 false。
B:AddOrGetExisting方法: 如果存在具有相同键的缓存项,则为指定缓存项的值;否则为 null。
C:Set方法:无返回值,至于存在相同键的情况,会是怎样呢?在后续测试章节中揭晓。
二. 框架封装
我们继续沿用上一章节中的封装思路,新建MemoryCacheHelp类,实现ICache接口,并封装自己特有的方法。
直接上代码吧。
1 /// <summary> 2 /// MemoryCache缓存 3 /// 需要引用using System.Runtime.Caching;程序集 4 /// 不支持缓存依赖 5 /// </summary> 6 public class MemoryCacheHelp : ICache 7 { 8 9 //一. 实例化的两种方式 10 11 #region 1.在属性中直接实例化MemoryCache 12 protected ObjectCache Cache 13 { 14 get 15 { 16 return MemoryCache.Default; 17 } 18 } 19 #endregion 20 21 #region 2.通过构造函数来实例化 22 //public ObjectCache Cache { get; set; } 23 //public MemoryCacheHelp() 24 //{ 25 // Cache = MemoryCache.Default; 26 //} 27 #endregion 28 29 //二. 实现接口中方法 30 31 #region 1.获取缓存的个数 32 /// <summary> 33 /// 获取缓存的个数 34 /// </summary> 35 public int Count 36 { 37 get 38 { 39 return (int)(Cache.GetCount()); 40 } 41 } 42 #endregion 43 44 #region 2.删除特定键的缓存 45 /// <summary> 46 /// 删除特定键的缓存 47 /// </summary> 48 /// <param name="key">键名</param> 49 public void Remove(string key) 50 { 51 Cache.Remove(key); 52 } 53 #endregion 54 55 #region 3.移除全部缓存 56 /// <summary> 57 /// 移除全部缓存 58 /// </summary> 59 public void RemoveAll() 60 { 61 foreach (var item in Cache) 62 { 63 Cache.Remove(item.Key); 64 } 65 } 66 #endregion 67 68 #region 4.根据键值获取特定类型的缓存 69 /// <summary> 70 /// 根据键值获取特定类型的缓存 71 /// </summary> 72 /// <typeparam name="T">泛型T</typeparam> 73 /// <param name="key">键名</param> 74 /// <returns></returns> 75 public T Get<T>(string key) 76 { 77 if (Cache.Contains(key)) 78 { 79 return (T)Cache[key]; 80 } 81 else 82 { 83 //此关键字对于引用类型会返回空,对于数值类型会返回零 84 return default(T); 85 } 86 } 87 #endregion 88 89 #region 5.判断缓存是否存在 90 /// <summary> 91 /// 缓存是否存在 92 /// </summary> 93 /// <param name="key">键名</param> 94 /// <returns>true:表示存在; false:表示不存在</returns> 95 public bool Contains(string key) 96 { 97 return Cache.Contains(key); 98 } 99 #endregion 100 101 #region 6.获取缓存值的类型(子类创建) 102 /// <summary> 103 /// 获取缓存值的类型 104 /// </summary> 105 /// <param name="key">键名</param> 106 /// <returns>键名对应的缓存值的类型</returns> 107 public Type GetCacheType(string key) 108 { 109 return Cache[key].GetType(); 110 } 111 #endregion 112 113 #region 7.增加或更新缓存(存在则更新,不存在则添加,采用绝对时间的模式) 114 /// <summary> 115 /// 增加或更新缓存 116 /// </summary> 117 /// <param name="key"></param> 118 /// <param name="value"></param> 119 /// <param name="cacheTime">绝对过期时间,默认为1天</param> 120 public void AddOrUpdate(string key, object value, int cacheTime = 1) 121 { 122 if (Cache.Contains(key)) 123 { 124 Cache.Remove(key); 125 } 126 var policy = new CacheItemPolicy(); 127 policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromDays(cacheTime); 128 Cache.Add(new CacheItem(key, value), policy); 129 } 130 131 #endregion 132 133 134 //三. 新增接口以外的方法 135 136 137 #region 1.获取全部缓存(子类创建-暂无办法实现) 138 public IEnumerator<KeyValuePair<string, object>> GetAllCache() 139 { 140 IEnumerator<KeyValuePair<string, object>> cacheList =null; 141 return cacheList; 142 } 143 #endregion 144 145 #region 2.Add模式增加缓存(子类创建) 146 /// <summary> 147 /// Add模式增加缓存(如果该缓存已经存在,返回false,不存在,返回true) 148 /// </summary> 149 /// <param name="key">键</param> 150 /// <param name="value">值</param> 151 /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00");</param> 152 /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param> 153 /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写 154 /// false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写 155 /// </param> 156 /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param> 157 /// <param name="UpdateCallback">缓存失效前的回调:含有一个参数的委托:CacheEntryUpdateArguments</param> 158 /// <param name="RemovedCallback">缓存失效后的回调:含有一个参数的委托:CacheEntryRemovedArguments</param> 159 public bool AddCache(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, 160 CacheItemPriority priority = CacheItemPriority.Default, CacheEntryUpdateCallback UpdateCallback = null, CacheEntryRemovedCallback RemovedCallback = null) 161 { 162 bool flag; 163 CacheItemPolicy policy = new CacheItemPolicy(); 164 policy.UpdateCallback = UpdateCallback; 165 policy.RemovedCallback = RemovedCallback; 166 policy.Priority = priority; 167 if (isAbsolute) 168 { 169 //绝对过期 170 policy.AbsoluteExpiration = absoluteExpiration; 171 flag = Cache.Add(key, value, policy); 172 173 } 174 else 175 { 176 //相对过期 177 policy.SlidingExpiration = slidingExpiration; 178 flag = Cache.Add(key, value, policy); 179 180 } 181 return flag; 182 } 183 #endregion 184 185 #region 3.AddOrGetExisting模式增加缓存(子类创建) 186 /// <summary> 187 /// AddOrGetExisting模式增加缓存(如果该缓存已经存在,返回该缓存的值,不存在,执行插入操作,返回null) 188 /// </summary> 189 /// <param name="key">键</param> 190 /// <param name="value">值</param> 191 /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00");</param> 192 /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param> 193 /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写 194 /// false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写 195 /// </param> 196 /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param> 197 /// <param name="UpdateCallback">缓存失效前的回调:含有一个参数的委托:CacheEntryUpdateArguments</param> 198 /// <param name="RemovedCallback">缓存失效后的回调:含有一个参数的委托:CacheEntryRemovedArguments</param> 199 public object AddOrGetExisting(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, 200 CacheItemPriority priority = CacheItemPriority.Default, CacheEntryUpdateCallback UpdateCallback = null, CacheEntryRemovedCallback RemovedCallback = null) 201 { 202 object flag; 203 CacheItemPolicy policy = new CacheItemPolicy(); 204 policy.UpdateCallback = UpdateCallback; 205 policy.RemovedCallback = RemovedCallback; 206 policy.Priority = priority; 207 if (isAbsolute) 208 { 209 //绝对过期 210 policy.AbsoluteExpiration = absoluteExpiration; 211 flag = Cache.AddOrGetExisting(key, value, policy); 212 213 } 214 else 215 { 216 //相对过期 217 policy.SlidingExpiration = slidingExpiration; 218 flag = Cache.AddOrGetExisting(key, value, policy); 219 220 } 221 return flag; 222 } 223 #endregion 224 225 #region 4.Set模式增加缓存(子类创建 需要测试存在和不存在时各自对应什么情况) 226 /// <summary> 227 /// Set模式增加缓存(如果该缓存已经存在,??,不存在,??) 228 /// </summary> 229 /// <param name="key">键</param> 230 /// <param name="value">值</param> 231 /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1); DateTime.Parse("2016-5-28 20:32:00");</param> 232 /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param> 233 /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写 234 /// false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写 235 /// </param> 236 /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param> 237 /// <param name="UpdateCallback">缓存失效前的回调:含有一个参数的委托:CacheEntryUpdateArguments</param> 238 /// <param name="RemovedCallback">缓存失效后的回调:含有一个参数的委托:CacheEntryRemovedArguments</param> 239 public void SetCache(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, 240 CacheItemPriority priority = CacheItemPriority.Default, CacheEntryUpdateCallback UpdateCallback = null, CacheEntryRemovedCallback RemovedCallback = null) 241 { 242 CacheItemPolicy policy = new CacheItemPolicy(); 243 policy.UpdateCallback = UpdateCallback; 244 policy.RemovedCallback = RemovedCallback; 245 policy.Priority = priority; 246 if (isAbsolute) 247 { 248 //绝对过期 249 policy.AbsoluteExpiration = absoluteExpiration; 250 Cache.Set(key, value, policy); 251 } 252 else 253 { 254 //相对过期 255 policy.SlidingExpiration = slidingExpiration; 256 Cache.Set(key, value, policy); 257 } 258 } 259 #endregion
如何使用,以及使用过程的问题,在后续章节中揭晓。