第一节:从程序集的角度分析System.Web.Caching.Cache ,并完成基本封装。

一. 揭开迷雾

1. 程序集准备

  a.  需要给项目添加 System.Web 程序集。

  

        b.  需要给使用的地方添加两个引用。

   

2. 程序集探究

     在对应的类中输入关键字 Cache,选中点击F12,查看Cache程序集,如下图所示:

     

     我们一起来分析从上往下来分析一下该程序集。

     (1). 两个字段,根据类型能看出来,一个是具体的时间点,另一个时间段,我们猜想,他们可能分别对应缓存中的绝对过期时间相对过期时间。(其实事实也是如此

  

    (2). 构造函数

       

      注意:通常我们实例化该类型的缓存,一般不直接通过构造函数实例化,我们通常使用 HttpRuntime.Cache 。我们一起来看看HttpRuntime的程序集,其中有个Cache属性,即可以通过它来获取Cache对象的实例。

     

  (3). 顾名思义通俗易懂的属性和方法。

   A : Count 属性,获取缓存个数。

            B : Get(string key) 方法,根据缓存的键名来获取缓存的值。

            C : Remove(string key) 方法,根据缓存的键名来删除缓存的值。

     

     (4). 深究  public IDictionaryEnumerator GetEnumerator();

     查看IDictionaryEnumerator的程序集,发现他是一个字典类型的集合,有键有值。

    

  那么问题来了,怎么遍历该字典类型的集合呢?怎么获取对应的键和值呢?F12查看 IEnumerator程序集,发现里面有一个MoveNext()方法,可以推进到集合的下一个元素。

    

    (5).  Add和Insert方法,二者都为增加缓存的方法,而且二者最多参数的那个重载参数类型完全相同。不同的是Insert有多种重载方式,而Add只有一种重载。 二者核心差异:当缓存已经存在,用Add添加会报错,但用Insert添加,会直接覆盖更新。

    下面以Add为例,一起来分析这七个参数。

    A:key: 代表缓存的键名。

    B:value:代表缓存的值,可以是任意类型。

    C:dependencies:表示缓存的依赖项,可以依赖文件、文件夹、多个文件、以及依赖数据库,如果不需要依赖时,传入参数null。

    D:absoluteExpiration:代表绝对过期时间,是个DateTime类型时间点。如果要启用绝对过期时间,那么slidingExpriation必须为:Cache.NoSlidingExpiration。    

     该参数表现形式可以是:如:DateTime.Now.AddDays(1);   DateTime.Parse("2016-5-28 20:32:00")  。

    E:slidingExpiration:代表相对过期时间,是个TimeSpan类型时间段。   如果要启用相对过期时间,那么absoluteExpiration必须为:Cache.NoAbsoluteExpiration

          该参数的表现形式可以是:: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒   。 

    F:priority:代表缓存销毁时的移除顺序,优先级低的先销毁。没有特殊要求通常使用: CacheItemPriority.Normal  即可。

    G:onRemoveCallBack:是一个无返回值具有三个参数的委托。public delegate void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason);

     当缓存过期时,调用该委托。委托的三个参数分别代表的含义为:缓存的键、缓存的值、缓存销毁的原因。

  

. 缓存封装

 1.  封装思路

  首先我们要清楚,封装的目的是什么? 说白了,方便自己、方便别人的灵活调用;同时便于以后的代码维护,能应对需求的变更。

       通常调用的方式有两种:1. 将方法写成static静态方法,直接通过   类名.方法名  来进行调用。(该种方式偏离了面向对象的体系)

                                               2. 将该类实例化,然后用实例化的对象调用该类中的封装方法。

                                               3. 这里暂时不考虑 IOC的方式创建对象。

       我们试想,会有什么需求变化呢? 有一天,PM要求,所有使用System.Web.Caching.Cache缓存的地方,都要改成 MemoryCache,如果我们事先没有应对措施,我的天!数不胜数的方法中均是传入的 Cache实例,不支持MemoryCache的实例,排着改?保证你崩溃!!!!!

       上述场景,在实际开发中非常常见,解决该问题,我们通常使用DIP原则进行封装(依赖倒置原则,核心面向接口编程)

  所以我们定义一个缓存接口ICache,约束了缓存的定义的规范,然后我们再建立一个 RuntimeCacheHelp 类,对ICache进行了实现,同时也定义自己特有的方法

 2.  话不多说,直接上代码。

  接口:

 1     /// <summary>
 2     /// 定义缓存接口
 3     /// </summary>
 4     public interface ICache
 5     {
 6         //1.缓存的个数只能获取,不能设置
 7         int Count { get; }
 8         //2. 删除特定键的缓存
 9         void Remove(string key);
10         //3.移除全部缓存
11         void RemoveAll();
12         //4.根据键值获取特定类型的缓存
13         T Get<T>(string key);
14         //5.判断缓存是否存在
15         bool Contains(string key);
16         //6. 获取缓存值的类型
17         Type GetCacheType(string key);
18         //7. 增加或更新缓存(存在则更新,不存在则添加,采用绝对时间的模式)
19         /// <param name="cacheTime">绝对过期时间,默认1天</param>
20         void AddOrUpdate(string key, object value,int cacheTime=1);
21        
22     }

  缓存帮助类:

  1 /// <summary>
  2     /// HttpRuntime缓存
  3     /// 需要引入:System.Web程序集
  4     /// 支持缓存依赖
  5     /// </summary>
  6     public class RuntimeCacheHelp : ICache
  7     {
  8         //一.实例化的两种方式
  9 
 10         #region 1.封装成属性
 11         protected Cache cache
 12         {
 13             get
 14             {
 15                 return HttpRuntime.Cache;
 16             }
 17         }
 18         #endregion
 19 
 20         #region 2.利用构造函数
 21 
 22         //public Cache cache2 { get; set; }
 23         //public RuntimeCacheHelp()
 24         //{
 25         //    cache2 = HttpRuntime.Cache;
 26         //} 
 27         #endregion
 28 
 29         //二. 实现接口中的方法
 30 
 31         #region 1.获取缓存的个数
 32         public int Count
 33         {
 34             get { return cache.Count; }
 35         }
 36         #endregion
 37 
 38         #region 2.删除特定键的缓存
 39         /// <summary>
 40         /// 删除特定键的缓存
 41         /// </summary>
 42         /// <param name="key">缓存的键名</param>
 43         public void Remove(string key)
 44         {
 45             cache.Remove(key);
 46         }
 47         #endregion
 48 
 49         #region 3.移除全部缓存
 50         /// <summary>
 51         /// 移除全部缓存
 52         /// </summary>
 53         public void RemoveAll()
 54         {
 55             IDictionaryEnumerator CacheEnum = cache.GetEnumerator();
 56             while (CacheEnum.MoveNext())
 57             {
 58                 cache.Remove(CacheEnum.Key.ToString());
 59             }
 60         }
 61 
 62         #endregion
 63 
 64         #region 4.根据键值获取特定类型的缓存
 65         /// <summary>
 66         /// 根据键值获取特定类型的缓存
 67         /// </summary>
 68         /// <typeparam name="T">泛型T</typeparam>
 69         /// <param name="key">键名</param>
 70         /// <returns></returns>
 71         public T Get<T>(string key)
 72         {
 73             //程序集中 this属性的应用
 74             if (cache[key] != null)
 75             {
 76                 return (T)cache[key];
 77             }
 78             return default(T);
 79         }
 80         #endregion
 81 
 82         #region 5.判断缓存是否存在
 83         /// <summary>
 84         /// 判断缓存是否存在
 85         /// </summary>
 86         /// <param name="key">键值</param>
 87         /// <returns>true代表存在;false代表不存在</returns>
 88         public bool Contains(string key)
 89         {
 90             return cache.Get(key) == null ? false : true;
 91         }
 92 
 93         #endregion
 94 
 95         #region 6.获取缓存值的类型(子类创建)
 96         /// <summary>
 97         /// 获取缓存值的类型
 98         /// </summary>
 99         /// <param name="key">键名</param>
100         /// <returns>键名对应的缓存值的类型</returns>
101         public Type GetCacheType(string key)
102         {
103             return cache[key].GetType();
104         }
105         #endregion
106 
107         #region 7.增加或更新缓存(存在则更新,不存在则添加,采用绝对时间的模式)
108         /// <summary>
109         /// 增加或更新缓存
110         /// </summary>
111         /// <param name="key"></param>
112         /// <param name="value"></param>
113         /// <param name="cacheTime">绝对过期时间,默认为1天</param>
114         public void AddOrUpdate(string key, object value, int cacheTime = 1)
115         {
116             var absoluteTime = DateTime.Now + TimeSpan.FromDays(cacheTime);
117             cache.Insert(key, value, null, absoluteTime, Cache.NoSlidingExpiration);
118         }
119 
120         #endregion
121 
122         //三. 子类创建的新方法
123 
124 
125         #region 1.获取全部缓存(子类创建)
126         public IDictionaryEnumerator GetAllCache()
127         {
128             IDictionaryEnumerator cacheList = cache.GetEnumerator();
129             //获取键值的方法
130             //while (cacheList.MoveNext())
131             //{
132             //    var key = cacheList.Key.ToString();
133             //    var value = cacheList.Value;
134             //}
135             return cacheList;
136         }
137         #endregion
138 
139         #region 2.Add模式增加缓存(子类创建)
140         /// <summary>
141         /// Add模式增加缓存(如果该缓存已经存在,再次添加会报错;Insert模式会覆盖上次)
142         /// </summary>
143         /// <param name="key"></param>
144         /// <param name="value"></param>
145         /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1);   DateTime.Parse("2016-5-28 20:32:00");</param>
146         /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param>
147         /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写
148         ///                          false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写
149         ///  </param>
150         /// <param name="dependencies">缓存依赖:可以依赖文件、文件夹、数据库表</param>
151         /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param>
152         /// <param name="onRemoveCallback">缓存失效后的回调:含有三个参数的委托,三个参数分别为(key,value,reason) 即(缓存的键、值、失效原因)</param>
153         public void AddCache(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, CacheDependency dependencies = null,
154             CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback onRemoveCallback = null)
155         {
156             if (isAbsolute)
157             {
158                 //绝对过期
159                 cache.Add(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration, priority, onRemoveCallback);
160             }
161             else
162             {
163                 //相对过期
164                 cache.Add(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback);
165             }
166         }
167         #endregion
168 
169         #region 3.Insert模式增加缓存(子类创建)
170         /// <summary>
171         /// Insert模式增加缓存(如果该缓存已经存在,会覆盖上次,Add模式则是报错)
172         /// </summary>
173         /// <param name="key"></param>
174         /// <param name="value"></param>
175         /// <param name="absoluteExpiration">绝对过期时间的参数:如:DateTime.Now.AddDays(1);   DateTime.Parse("2016-5-28 20:32:00");</param>
176         /// <param name="slidingExpiration">相对过期时间的参数: 如:new TimeSpan(0,0, 0, 2) 天,小时,分钟,秒</param>
177         /// <param name="isAbsolute">true代表使用绝对过期时间,填写absoluteExpiration参数,slidingExpiration忽略不需要填写
178         ///                          false代表使用绝对过期时间,填写slidingExpiration 参数, absoluteExpiration忽略不需要填写
179         ///  </param>
180         /// <param name="dependencies">缓存依赖:可以依赖文件、文件夹、数据库表</param>
181         /// <param name="priority">缓存销毁时的优先级,没有特别要求,使用该封装的默认即可</param>
182         /// <param name="onRemoveCallback">缓存失效后的回调:含有三个参数的委托,三个参数分别为(key,value,reason) 即(缓存的键、值、失效原因)</param>
183         public void InsertCache(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, bool isAbsolute = true, CacheDependency dependencies = null,
184             CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback onRemoveCallback = null)
185         {
186             if (isAbsolute)
187             {
188                 //绝对过期
189                 cache.Insert(key, value, dependencies, absoluteExpiration, Cache.NoSlidingExpiration, priority, onRemoveCallback);
190             }
191             else
192             {
193                 //相对过期
194                 cache.Insert(key, value, dependencies, Cache.NoAbsoluteExpiration, slidingExpiration, priority, onRemoveCallback);
195             }
196         }
197         #endregion

  3. 如何调用?调用过程中会存在哪些问题?我们再后续章节中进行介绍。

原文地址:https://www.cnblogs.com/yaopengfei/p/7234016.html