C# 缓存工厂类

描 述:缓存工厂类

 1     /// <summary>               
 2     ///     描 述:缓存工厂类
 3     /// </summary>
 4     public class CacheFactory
 5     {
 6 
 7         /// <summary>
 8         ///     定义通用的Repository
 9         /// </summary>
10         /// <returns></returns>
11         public static ICacheService Cache()
12         {
13             var cacheType = Config.GetValue("CacheType");
14             switch (cacheType)
15             {
16                 case "MemoryCache":
17                     return new MemoryCacheService(null);
18 
19                 case "RedisCache":
20                     return new RedisCacheService();
21 
22                 default:
23                     return new MemoryCacheService(null);
24             }
25         }
26     }

描 述:缓存接口

  1     public interface ICacheService
  2     {
  3 
  4         /// <summary>
  5         /// 验证缓存项是否存在
  6         /// </summary>
  7         /// <param name="key">缓存Key</param>
  8         /// <returns></returns>
  9         bool Exists(string key);
 10 
 11         /// <summary>
 12         /// 验证缓存项是否存在(异步方式)
 13         /// </summary>
 14         /// <param name="key">缓存Key</param>
 15         /// <returns></returns>
 16         //Task<bool> ExistsAsync(string key);
 17 
 18 
 19 
 20         /// <summary>
 21         /// 添加缓存
 22         /// </summary>
 23         /// <param name="key">缓存Key</param>
 24         /// <param name="value">缓存Value</param>
 25         /// <returns></returns>
 26         bool Add(string key, object value);
 27 
 28         /// <summary>
 29         /// 添加缓存(异步方式)
 30         /// </summary>
 31         /// <param name="key">缓存Key</param>
 32         /// <param name="value">缓存Value</param>
 33         /// <returns></returns>
 34         //Task<bool> AddAsync(string key, object value);
 35 
 36         /// <summary>
 37         /// 添加缓存
 38         /// </summary>
 39         /// <param name="key">缓存Key</param>
 40         /// <param name="value">缓存Value</param>
 41         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
 42         /// <param name="expiressAbsoulte">绝对过期时长</param>
 43         /// <returns></returns>
 44         bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
 45 
 46         /// <summary>
 47         /// 添加缓存(异步方式)
 48         /// </summary>
 49         /// <param name="key">缓存Key</param>
 50         /// <param name="value">缓存Value</param>
 51         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
 52         /// <param name="expiressAbsoulte">绝对过期时长</param>
 53         /// <returns></returns>
 54         //Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
 55 
 56         /// <summary>
 57         /// 添加缓存
 58         /// </summary>
 59         /// <param name="key">缓存Key</param>
 60         /// <param name="value">缓存Value</param>
 61         /// <param name="expiresIn">缓存时长</param>
 62         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
 63         /// <returns></returns>
 64         bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false);
 65 
 66         /// <summary>
 67         /// 添加缓存(异步方式)
 68         /// </summary>
 69         /// <param name="key">缓存Key</param>
 70         /// <param name="value">缓存Value</param>
 71         /// <param name="expiresIn">缓存时长</param>
 72         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
 73         /// <returns></returns>
 74         //Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
 75 
 76 
 77 
 78         /// <summary>
 79         /// 删除缓存
 80         /// </summary>
 81         /// <param name="key">缓存Key</param>
 82         /// <returns></returns>
 83         bool Remove(string key);
 84 
 85         /// <summary>
 86         /// 删除缓存(异步方式)
 87         /// </summary>
 88         /// <param name="key">缓存Key</param>
 89         /// <returns></returns>
 90         //Task<bool> RemoveAsync(string key);
 91 
 92         /// <summary>
 93         /// 批量删除缓存
 94         /// </summary>
 95         /// <param name="key">缓存Key集合</param>
 96         /// <returns></returns>
 97         void RemoveAll(IEnumerable<string> keys);
 98 
 99         /// <summary>
100         /// 批量删除缓存(异步方式)
101         /// </summary>
102         /// <param name="key">缓存Key集合</param>
103         /// <returns></returns>
104         //Task RemoveAllAsync(IEnumerable<string> keys);
105 
106 
107 
108         /// <summary>
109         /// 获取缓存
110         /// </summary>
111         /// <param name="key">缓存Key</param>
112         /// <returns></returns>
113         T Get<T>(string key) where T : class;
114 
115         /// <summary>
116         /// 获取缓存(异步方式)
117         /// </summary>
118         /// <param name="key">缓存Key</param>
119         /// <returns></returns>
120         //Task<T> GetAsync<T>(string key) where T : class;
121 
122         /// <summary>
123         /// 获取缓存
124         /// </summary>
125         /// <param name="key">缓存Key</param>
126         /// <returns></returns>
127         object Get(string key);
128 
129         /// <summary>
130         /// 获取缓存(异步方式)
131         /// </summary>
132         /// <param name="key">缓存Key</param>
133         /// <returns></returns>
134         //Task<object> GetAsync(string key);
135 
136         /// <summary>
137         /// 获取缓存集合
138         /// </summary>
139         /// <param name="keys">缓存Key集合</param>
140         /// <returns></returns>
141         IDictionary<string, object> GetAll(IEnumerable<string> keys);
142 
143         /// <summary>
144         /// 获取缓存集合(异步方式)
145         /// </summary>
146         /// <param name="keys">缓存Key集合</param>
147         /// <returns></returns>
148         //Task<IDictionary<string, object>> GetAllAsync(IEnumerable<string> keys);
149 
150 
151 
152 
153         /// <summary>
154         /// 修改缓存
155         /// </summary>
156         /// <param name="key">缓存Key</param>
157         /// <param name="value">新的缓存Value</param>
158         /// <returns></returns>
159         bool Replace(string key, object value);
160 
161         /// <summary>
162         /// 修改缓存(异步方式)
163         /// </summary>
164         /// <param name="key">缓存Key</param>
165         /// <param name="value">新的缓存Value</param>
166         /// <returns></returns>
167         //Task<bool> ReplaceAsync(string key, object value);
168 
169         /// <summary>
170         /// 修改缓存
171         /// </summary>
172         /// <param name="key">缓存Key</param>
173         /// <param name="value">新的缓存Value</param>
174         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
175         /// <param name="expiressAbsoulte">绝对过期时长</param>
176         /// <returns></returns>
177         bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
178 
179         /// <summary>
180         /// 修改缓存(异步方式)
181         /// </summary>
182         /// <param name="key">缓存Key</param>
183         /// <param name="value">新的缓存Value</param>
184         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
185         /// <param name="expiressAbsoulte">绝对过期时长</param>
186         /// <returns></returns>
187         //Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
188 
189         /// <summary>
190         /// 修改缓存
191         /// </summary>
192         /// <param name="key">缓存Key</param>
193         /// <param name="value">新的缓存Value</param>
194         /// <param name="expiresIn">缓存时长</param>
195         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
196         /// <returns></returns>
197         bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false);
198 
199         /// <summary>
200         /// 修改缓存(异步方式)
201         /// </summary>
202         /// <param name="key">缓存Key</param>
203         /// <param name="value">新的缓存Value</param>
204         /// <param name="expiresIn">缓存时长</param>
205         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
206         /// <returns></returns>
207         //Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
208 
209 
210 
211 
212 
213     }

描 述 :MemoryCache

  1  public class MemoryCacheService : ICacheService
  2     {
  3         protected IMemoryCache Cache;
  4         public MemoryCacheService(IMemoryCache _cache)
  5         {
  6             Cache = _cache;
  7         }
  8 
  9         /// <summary>
 10         /// 验证缓存项是否存在
 11         /// </summary>
 12         /// <param name="key">缓存Key</param>
 13         /// <returns></returns>
 14         public bool Exists(string key)
 15         {
 16             if (key == null)
 17             {
 18                 throw new ArgumentNullException(nameof(key));
 19             }
 20             object cached;
 21             return Cache.TryGetValue(key, out cached);
 22         }
 23         /// <summary>
 24         /// 添加缓存
 25         /// </summary>
 26         /// <param name="key">缓存Key</param>
 27         /// <param name="value">缓存Value</param>
 28         /// <returns></returns>
 29         public bool Add(string key, object value)
 30         {
 31             if (key == null)
 32             {
 33                 throw new ArgumentNullException(nameof(key));
 34             }
 35             if (value == null)
 36             {
 37                 throw new ArgumentNullException(nameof(value));
 38             }
 39             Cache.Set(key, value);
 40             return Exists(key);
 41         }
 42         /// <summary>
 43         /// 添加缓存
 44         /// </summary>
 45         /// <param name="key">缓存Key</param>
 46         /// <param name="value">缓存Value</param>
 47         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
 48         /// <param name="expiressAbsoulte">绝对过期时长</param>
 49         /// <returns></returns>
 50         public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
 51         {
 52             if (key == null)
 53             {
 54                 throw new ArgumentNullException(nameof(key));
 55             }
 56             if (value == null)
 57             {
 58                 throw new ArgumentNullException(nameof(value));
 59             }
 60             Cache.Set(key, value,
 61                     new MemoryCacheEntryOptions()
 62                     .SetSlidingExpiration(expiresSliding)
 63                     .SetAbsoluteExpiration(expiressAbsoulte)
 64                     );
 65 
 66             return Exists(key);
 67         }
 68         /// <summary>
 69         /// 添加缓存
 70         /// </summary>
 71         /// <param name="key">缓存Key</param>
 72         /// <param name="value">缓存Value</param>
 73         /// <param name="expiresIn">缓存时长</param>
 74         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
 75         /// <returns></returns>
 76         public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
 77         {
 78             if (key == null)
 79             {
 80                 throw new ArgumentNullException(nameof(key));
 81             }
 82             if (value == null)
 83             {
 84                 throw new ArgumentNullException(nameof(value));
 85             }
 86             if (isSliding)
 87                 Cache.Set(key, value,
 88                     new MemoryCacheEntryOptions()
 89                     .SetSlidingExpiration(expiresIn)
 90                     );
 91             else
 92                 Cache.Set(key, value,
 93                 new MemoryCacheEntryOptions()
 94                 .SetAbsoluteExpiration(expiresIn)
 95                 );
 96 
 97             return Exists(key);
 98         }
 99         /// <summary>
100         /// 删除缓存
101         /// </summary>
102         /// <param name="key">缓存Key</param>
103         /// <returns></returns>
104         public bool Remove(string key)
105         {
106             if (key == null)
107             {
108                 throw new ArgumentNullException(nameof(key));
109             }
110             Cache.Remove(key);
111 
112             return !Exists(key);
113         }
114         /// <summary>
115         /// 批量删除缓存
116         /// </summary>
117         /// <param name="key">缓存Key集合</param>
118         /// <returns></returns>
119         public void RemoveAll(IEnumerable<string> keys)
120         {
121             if (keys == null)
122             {
123                 throw new ArgumentNullException(nameof(keys));
124             }
125 
126             keys.ToList().ForEach(item => Cache.Remove(item));
127         }
128 
129         /// <summary>
130         /// 获取缓存
131         /// </summary>
132         /// <param name="key">缓存Key</param>
133         /// <returns></returns>
134         public T Get<T>(string key) where T : class
135         {
136             if (key == null)
137             {
138                 throw new ArgumentNullException(nameof(key));
139             }
140             return Cache.Get(key) as T;
141         }
142         /// <summary>
143         /// 获取缓存
144         /// </summary>
145         /// <param name="key">缓存Key</param>
146         /// <returns></returns>
147         public object Get(string key)
148         {
149             if (key == null)
150             {
151                 throw new ArgumentNullException(nameof(key));
152             }
153             return Cache.Get(key);
154         }
155         /// <summary>
156         /// 获取缓存集合
157         /// </summary>
158         /// <param name="keys">缓存Key集合</param>
159         /// <returns></returns>
160         public IDictionary<string, object> GetAll(IEnumerable<string> keys)
161         {
162             if (keys == null)
163             {
164                 throw new ArgumentNullException(nameof(keys));
165             }
166 
167             var dict = new Dictionary<string, object>();
168 
169             keys.ToList().ForEach(item => dict.Add(item, Cache.Get(item)));
170 
171             return dict;
172         }
173 
174         /// <summary>
175         /// 修改缓存
176         /// </summary>
177         /// <param name="key">缓存Key</param>
178         /// <param name="value">新的缓存Value</param>
179         /// <returns></returns>
180         public bool Replace(string key, object value)
181         {
182             if (key == null)
183             {
184                 throw new ArgumentNullException(nameof(key));
185             }
186             if (value == null)
187             {
188                 throw new ArgumentNullException(nameof(value));
189             }
190             if (Exists(key))
191                 if (!Remove(key)) return false;
192 
193             return Add(key, value);
194 
195         }
196         /// <summary>
197         /// 修改缓存
198         /// </summary>
199         /// <param name="key">缓存Key</param>
200         /// <param name="value">新的缓存Value</param>
201         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
202         /// <param name="expiressAbsoulte">绝对过期时长</param>
203         /// <returns></returns>
204         public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
205         {
206             if (key == null)
207             {
208                 throw new ArgumentNullException(nameof(key));
209             }
210             if (value == null)
211             {
212                 throw new ArgumentNullException(nameof(value));
213             }
214             if (Exists(key))
215                 if (!Remove(key)) return false;
216 
217             return Add(key, value, expiresSliding, expiressAbsoulte);
218         }
219         /// <summary>
220         /// 修改缓存
221         /// </summary>
222         /// <param name="key">缓存Key</param>
223         /// <param name="value">新的缓存Value</param>
224         /// <param name="expiresIn">缓存时长</param>
225         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
226         /// <returns></returns>
227         public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false)
228         {
229             if (key == null)
230             {
231                 throw new ArgumentNullException(nameof(key));
232             }
233             if (value == null)
234             {
235                 throw new ArgumentNullException(nameof(value));
236             }
237             if (Exists(key))
238                 if (!Remove(key)) return false;
239 
240             return Add(key, value, expiresIn, isSliding);
241         }
242 
243         public void Dispose()
244         {
245             if (Cache != null)
246                 Cache.Dispose();
247             GC.SuppressFinalize(this);
248         }
249 
250 
251 
252 
253     }

描 述: RedisCache

  1  public class RedisCacheService : ICacheService
  2     {
  3         public RedisCacheService(/*RedisCacheOptions options, int database = 0*/)
  4         //这里可以做成依赖注入,但没打算做成通用类库,所以直接把连接信息直接写在帮助类里
  5         {
  6             RedisCacheOptions options = new RedisCacheOptions
  7             {
  8                 Configuration = "127.0.0.1:6379",
  9                 InstanceName = "RedisCacheService_u48H4GU583hyehdH43"
 10             };
 11             //RedisConfig.Connection;
 12             // RedisConfig.InstanceName;
 13             int database = 0; //RedisConfig.DefaultDatabase;
 14             _connection = ConnectionMultiplexer.Connect(options.Configuration);
 15             Cache = _connection.GetDatabase(database);
 16             _instance = options.InstanceName;
 17         }
 18         protected IDatabase Cache;
 19         private readonly ConnectionMultiplexer _connection;
 20         private readonly string _instance;
 21 
 22         //public RedisCacheService(RedisCacheOptions options, int database = 0)
 23         //{
 24         //    _connection = ConnectionMultiplexer.Connect(options.Configuration);
 25         //    Cache = _connection.GetDatabase(database);
 26         //    _instance = options.InstanceName;
 27         //}
 28         public string GetKeyForRedis(string key)
 29         {
 30             return _instance + key;
 31         }
 32 
 33 
 34         /// <summary>
 35         /// 验证缓存项是否存在
 36         /// </summary>
 37         /// <param name="key">缓存Key</param>
 38         /// <returns></returns>
 39         public bool Exists(string key)
 40         {
 41             if (key == null)
 42             {
 43                 throw new ArgumentNullException(nameof(key));
 44             }
 45             return Cache.KeyExists(GetKeyForRedis(key));
 46         }
 47 
 48         /// <summary>
 49         /// 添加缓存
 50         /// </summary>
 51         /// <param name="key">缓存Key</param>
 52         /// <param name="value">缓存Value</param>
 53         /// <returns></returns>
 54         public bool Add(string key, object value)
 55         {
 56             if (key == null)
 57             {
 58                 throw new ArgumentNullException(nameof(key));
 59             }
 60             return Cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)));
 61         }
 62         /// <summary>
 63         /// 添加缓存
 64         /// </summary>
 65         /// <param name="key">缓存Key</param>
 66         /// <param name="value">缓存Value</param>
 67         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效)</param>
 68         /// <param name="expiressAbsoulte">绝对过期时长</param>
 69         /// <returns></returns>
 70         public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
 71         {
 72             if (key == null)
 73             {
 74                 throw new ArgumentNullException(nameof(key));
 75             }
 76             return Cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiressAbsoulte);
 77         }
 78         /// <summary>
 79         /// 添加缓存
 80         /// </summary>
 81         /// <param name="key">缓存Key</param>
 82         /// <param name="value">缓存Value</param>
 83         /// <param name="expiresIn">缓存时长</param>
 84         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效)</param>
 85         /// <returns></returns>
 86         public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
 87         {
 88             if (key == null)
 89             {
 90                 throw new ArgumentNullException(nameof(key));
 91             }
 92 
 93 
 94             return Cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiresIn);
 95         }/// <summary>
 96          /// 删除缓存
 97          /// </summary>
 98          /// <param name="key">缓存Key</param>
 99          /// <returns></returns>
100         public bool Remove(string key)
101         {
102             if (key == null)
103             {
104                 throw new ArgumentNullException(nameof(key));
105             }
106             return Cache.KeyDelete(GetKeyForRedis(key));
107         }
108         /// <summary>
109         /// 批量删除缓存
110         /// </summary>
111         /// <param name="key">缓存Key集合</param>
112         /// <returns></returns>
113         public void RemoveAll(IEnumerable<string> keys)
114         {
115             if (keys == null)
116             {
117                 throw new ArgumentNullException(nameof(keys));
118             }
119 
120             keys.ToList().ForEach(item => Remove(GetKeyForRedis(item)));
121         }
122 
123 
124 
125         /// <summary>
126         /// 获取缓存
127         /// </summary>
128         /// <param name="key">缓存Key</param>
129         /// <returns></returns>
130         public T Get<T>(string key) where T : class
131         {
132             if (key == null)
133             {
134                 throw new ArgumentNullException(nameof(key));
135             }
136 
137             var value = Cache.StringGet(GetKeyForRedis(key));
138 
139             if (!value.HasValue)
140             {
141                 return default(T);
142             }
143 
144             return JsonConvert.DeserializeObject<T>(value);
145         }
146         /// <summary>
147         /// 获取缓存
148         /// </summary>
149         /// <param name="key">缓存Key</param>
150         /// <returns></returns>
151         public object Get(string key)
152         {
153             if (key == null)
154             {
155                 throw new ArgumentNullException(nameof(key));
156             }
157 
158             var value = Cache.StringGet(GetKeyForRedis(key));
159 
160             if (!value.HasValue)
161             {
162                 return null;
163             }
164 
165 
166             return JsonConvert.DeserializeObject(value);
167         }
168         /// <summary>
169         /// 获取缓存集合
170         /// </summary>
171         /// <param name="keys">缓存Key集合</param>
172         /// <returns></returns>
173         public IDictionary<string, object> GetAll(IEnumerable<string> keys)
174         {
175             if (keys == null)
176             {
177                 throw new ArgumentNullException(nameof(keys));
178             }
179             var dict = new Dictionary<string, object>();
180 
181             keys.ToList().ForEach(item => dict.Add(item, Get(GetKeyForRedis(item))));
182 
183             return dict;
184         }
185         /// <summary>
186         /// 修改缓存
187         /// </summary>
188         /// <param name="key">缓存Key</param>
189         /// <param name="value">新的缓存Value</param>
190         /// <returns></returns>
191         public bool Replace(string key, object value)
192         {
193             if (key == null)
194             {
195                 throw new ArgumentNullException(nameof(key));
196             }
197 
198             if (Exists(key))
199                 if (!Remove(key))
200                     return false;
201 
202             return Add(key, value);
203 
204         }
205         /// <summary>
206         /// 修改缓存
207         /// </summary>
208         /// <param name="key">缓存Key</param>
209         /// <param name="value">新的缓存Value</param>
210         /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
211         /// <param name="expiressAbsoulte">绝对过期时长</param>
212         /// <returns></returns>
213         public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
214         {
215             if (key == null)
216             {
217                 throw new ArgumentNullException(nameof(key));
218             }
219 
220             if (Exists(key))
221                 if (!Remove(key))
222                     return false;
223 
224             return Add(key, value, expiresSliding, expiressAbsoulte);
225         }
226         /// <summary>
227         /// 修改缓存
228         /// </summary>
229         /// <param name="key">缓存Key</param>
230         /// <param name="value">新的缓存Value</param>
231         /// <param name="expiresIn">缓存时长</param>
232         /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
233         /// <returns></returns>
234         public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false)
235         {
236             if (key == null)
237             {
238                 throw new ArgumentNullException(nameof(key));
239             }
240 
241             if (Exists(key))
242                 if (!Remove(key)) return false;
243 
244             return Add(key, value, expiresIn, isSliding);
245         }
246         public void Dispose()
247         {
248             if (_connection != null)
249                 _connection.Dispose();
250             GC.SuppressFinalize(this);
251         }
252 
253 
254 
255 
256 
257     }

猜你喜欢

转载自www.cnblogs.com/hghg/p/10188548.html