C# 实现 key-value 结构自定义缓存 CustomCache
创始人
2024-06-01 11:12:28

功能需求

使用 C# 编写一个 key-value 结构进程内缓存,实现数据的缓存操作,此处所用到的知识点如下:

  • 线程安全的字典 ConcurrentDictionary
  • 设计模式之单例模式(Singleton);
  • 缓存数据【主动 & 被动】过期模式;

cache

key-value 缓存实现

说明:此处基于 .net 6 平台创建控制台项目。

  • 新建 ConsoleApp 项目,添加 CustomCacheHelper.cs 类;
  1. 导入命名空间(namespace
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
  1. CustomCacheHelper.cs 类中编写实现方法
/// 
/// 自定义内存缓存助手
/// 
public sealed class CustomCacheHelper
{#region 单例模式//创建私有化静态obj锁  private static readonly object _ObjLock = new();//创建私有静态字段,接收类的实例化对象  private static volatile CustomCacheHelper? _Instance = null;//构造函数私有化  private CustomCacheHelper() { }//创建单利对象资源并返回  public static CustomCacheHelper GetSingleObj(){if (_Instance == null){lock (_ObjLock){if (_Instance == null){_Instance = new CustomCacheHelper();}}}return _Instance;}#endregion/// /// 缓存字典 => 【key|value|time】/// private static volatile ConcurrentDictionary> _CacheDictionary = new();/// /// 1.主动过期/// static CustomCacheHelper(){Task.Run(() => {while (true){int millisecondsTimeout = 1000 * 60 * 10;Thread.Sleep(millisecondsTimeout); //10分钟检查一次if (_CacheDictionary != null && _CacheDictionary.Keys.Count > 0){ICollection listKey = _CacheDictionary.Keys;foreach (var key in listKey){var valueTime = _CacheDictionary[key];if (valueTime.Value < DateTime.Now){_CacheDictionary.TryRemove(key, out KeyValuePair value);}}}}});}/// /// 索引器/// /// /// public object this[string key]{get => _CacheDictionary[key];set => _CacheDictionary[key] = new KeyValuePair(value, null);}/// /// 设置相对过期缓存/// /// 键/// 数据包/// 相对过期时间public void Set(string key, object data, int seconds){var expirationTime = DateTime.Now.AddSeconds(seconds);_CacheDictionary[key] = new KeyValuePair(data, expirationTime);}/// /// 设置绝对过期缓存/// /// 键</// 数据包public void Set(string key, object data){this[key] = data; // 下面代码等效// _CacheDictionary[key] = new KeyValuePair(data, null);}/// /// 通过key获取缓存value/// 2.被动过期/// /// /// /// public T? Get(string key){if (Exist(key)){//var valueTime = _CacheDictionary[key];//return (T)valueTime.Key; //return (T)this[key];bool hasValue = _CacheDictionary.TryGetValue(key, out KeyValuePair value);if (hasValue){return (T)value.Key; //return (T)this[key];}}return default;}/// /// 获取所有的key/// /// public ICollection GetKeys() => _CacheDictionary.Keys;/// /// 获取缓存个数/// /// public int Count(){int count = 0;if (_CacheDictionary != null){count = _CacheDictionary.Count;}return count;}/// /// 删除指定key的value/// /// public void Remove(string key){if (Exist(key)){_CacheDictionary.TryRemove(key, out KeyValuePair value);}}/// /// 清空所有缓存/// public void Cleaner(){if (_CacheDictionary != null && _CacheDictionary.Count > 0){foreach (var key in _CacheDictionary.Keys){_CacheDictionary.TryRemove(key, out KeyValuePair value);}}}/// /// 2.被动过期,保证任何过期缓存都无法取值/// 检查key是否存在/// /// /// public bool Exist(string key){bool isExist = false;if (!string.IsNullOrWhiteSpace(key) && _CacheDictionary.ContainsKey(key)){var valTime = _CacheDictionary[key];if (valTime.Value != null && valTime.Value > DateTime.Now){isExist = true; //缓存没过期}else{if (valTime.Value == null){isExist = true; //永久缓存}else{_CacheDictionary.TryRemove(key, out KeyValuePair value); //缓存过期清理}}}return isExist;}
}

Main 方法使用缓存

由于该项目是采用控制台程序编写,我们可直接在 Main 方法中,添加如下代码:

var customCache = CustomCacheHelper.GetSingleObj();
customCache.Set("key1", "value1");
customCache.Set("key2", "value2", 3);
customCache.Set("key3", "value3", 6);
var keys = customCache.GetKeys();Console.WriteLine("首次打印:");
foreach (var key in keys)
{Console.WriteLine($"time:{DateTime.Now},key={key},value={customCache.Get(key)}");
}Console.WriteLine("睡眠5s后再次打印:");
Thread.Sleep(5000);
foreach (var key in keys)
{Console.WriteLine($"time:{DateTime.Now},key={key},value={customCache.Get(key)}");
}

此处代码中我们添加了三组 key-vaule 数据,其中一个是没有设置过期时间,另外两个设置过期时间,保存数据后,分别打印缓存中保存的数据,再第二次缓存打印前,先让线程睡眠等待 5 秒(5000毫秒),注意观察控制台输出的信息。

ConsoleApp 启动测试

从控制台输出的信息中,我们可以看到 key=key2value 值为空,说明我们内部调用 Exist 方法生效了,key2value 缓存有效时间是 3 秒,第二次打印输出信息时,此时已经睡眠 5 秒,相对于 key2 存储的内存数据已经超时,而 key3value 存储的有效时间是 6 秒,没有超时,所以能个获取到对应的内存数据。

启动测试

通过上面的 demo 演示,我们就实现了一个自定义的进程内缓存助手,在项目中可以很方便的导入使用。

相关内容

热门资讯

大雪和火锅更配,年轻人爱上吃清... 转自:贝壳财经 【#大雪和火锅更配#,#年轻人爱上吃清淡...
伦敦希思罗机场多人遭喷雾袭击受... 【#伦敦希思罗机场多人遭喷雾袭击受伤#】#通往希思罗机场铁路线已重新开放#伦敦警方称,多名男子用类似...
首批北证50成份指数基金面市三... Wind数据显示,截至12月5日,于2022年12月成立的首批8只北证50成份指数型基金,成立以来的...
奇点资本副总裁王苒:财务投资和... 奇点资本副总裁王苒表示,历经萌芽起步、高速发展后的创投行业,近年来正处于结构调整期,一个比较明显的变...
成交活跃度走高,创业板指估值领... (来源:一观大势)作者:方奕/李健核心观点:上周(2025/12/1-2025/12/5)成交活跃度...