C# 实现 key-value 结构自定义缓存 CustomCache

C#中的KeyValuePair使用详解 在上面的示例中,我们定义了一个方法ProcessKeyValuePair,它接受一个KeyValuePair作为参数,并执行一些处理逻辑。在上面的示例中,我们创建了一个字典对象dictionary,并向其添加两个KeyValuePair元素。要创建一个KeyValuePair对象,可以使用KeyValuePair构造函数,该构造函数接受键和值作为参数。在上面的示例中,我们创建了一个KeyValuePair对象,键是字符串类型,值是整数类型。键是"key",值是10。如果您有任何疑问,请随时提问。 阅读详情

功能需求

使用 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 类中编写实现方法
/// <summary>
/// 自定义内存缓存助手
/// </summary>
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

    /// <summary>
    /// 缓存字典 => 【key|value|time】
    /// </summary>
    private static volatile ConcurrentDictionary<string, KeyValuePair<object, DateTime?>> _CacheDictionary = new();

    /// <summary>
    /// 1.主动过期
    /// </summary>
    static CustomCacheHelper()
    {
        Task.Run(() => {
            while (true)
            {
                int millisecondsTimeout = 1000 * 60 * 10;
                Thread.Sleep(millisecondsTimeout); //10分钟检查一次

                if (_CacheDictionary != null && _CacheDictionary.Keys.Count > 0)
                {
                    ICollection<string> listKey = _CacheDictionary.Keys;
                    foreach (var key in listKey)
                    {
                        var valueTime = _CacheDictionary[key];
                        if (valueTime.Value < DateTime.Now)
                        {
                            _CacheDictionary.TryRemove(key, out KeyValuePair<object, DateTime?> value);
                        }
                    }
                }
            }
        });
    }

    /// <summary>
    /// 索引器
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public object this[string key]
    {
        get => _CacheDictionary[key];
        set => _CacheDictionary[key] = new KeyValuePair<object, DateTime?>(value, null);
    }

    /// <summary>
    /// 设置相对过期缓存
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="data">数据包</param>
    /// <param name="seconds">相对过期时间</param>
    public void Set(string key, object data, int seconds)
    {
        var expirationTime = DateTime.Now.AddSeconds(seconds);
        _CacheDictionary[key] = new KeyValuePair<object, DateTime?>(data, expirationTime);
    }

    /// <summary>
    /// 设置绝对过期缓存
    /// </summary>
    /// <param name="key">键<</param>
    /// <param name="data">数据包</param>
    public void Set(string key, object data)
    {
        this[key] = data; // 下面代码等效
        // _CacheDictionary[key] = new KeyValuePair<object, DateTime?>(data, null);
    }

    /// <summary>
    /// 通过key获取缓存value
    /// 2.被动过期
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public T? Get<T>(string key)
    {
        if (Exist(key))
        {
            //var valueTime = _CacheDictionary[key];
            //return (T)valueTime.Key; //return (T)this[key];

            bool hasValue = _CacheDictionary.TryGetValue(key, out KeyValuePair<object, DateTime?> value);
            if (hasValue)
            {
                return (T)value.Key; //return (T)this[key];
            }
        }

        return default;
    }

    /// <summary>
    /// 获取所有的key
    /// </summary>
    /// <returns></returns>
    public ICollection<string> GetKeys() => _CacheDictionary.Keys;

    /// <summary>
    /// 获取缓存个数
    /// </summary>
    /// <returns></returns>
    public int Count()
    {
        int count = 0;
        if (_CacheDictionary != null)
        {
            count = _CacheDictionary.Count;
        }
        return count;
    }

    /// <summary>
    /// 删除指定key的value
    /// </summary>
    /// <param name="key"></param>
    public void Remove(string key)
    {
        if (Exist(key))
        {
            _CacheDictionary.TryRemove(key, out KeyValuePair<object, DateTime?> value);
        }
    }

    /// <summary>
    /// 清空所有缓存
    /// </summary>
    public void Cleaner()
    {
        if (_CacheDictionary != null && _CacheDictionary.Count > 0)
        {
            foreach (var key in _CacheDictionary.Keys)
            {
                _CacheDictionary.TryRemove(key, out KeyValuePair<object, DateTime?> value);
            }
        }
    }

    /// <summary>
    /// 2.被动过期,保证任何过期缓存都无法取值
    /// 检查key是否存在
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    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<object, DateTime?> 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<string>(key)}");
}

Console.WriteLine("睡眠5s后再次打印:");
Thread.Sleep(5000);
foreach (var key in keys)
{
    Console.WriteLine($"time:{DateTime.Now},key={key},value={customCache.Get<string>(key)}");
}

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

ConsoleApp 启动测试

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

启动测试

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

C#中使用字典实现键值对存储 字典的声明方式与其他变量类似,可以使用 var 关键字进行类型推断,也可以指定具体的类型。在C#编程语言中,字典(Dictionary)是一种常用的数据结构,它可以用于存储和操作键值对。字典能够高效地根据给定的键(key)查找和访问对应的值(value),因此在实际开发中经常被使用。如果指定的键已经存在于字典中,那么新的值将替换原有的值。字典提供了高效的键值对存储和操作,非常适合在需要快速查找、访问和更新数据的场景中使用。需要注意的是,如果字典中不存在指定的键,则会抛出异常。C#中使用字典实现键值对存储。 阅读详情

相关推荐

kali设置安装burpsuite中文版

工具:通过网盘分享的文件:Burpsuite 链接:提取码: jay1。

m0_74786138的博客 5202

数据缓存助手类

using System; using System.Collections.Generic; using System.Text; using System.Web.Caching; using System.Web.UI; namespace ASPNETCaCheHelpers { /// /// 在ASPNET应用程序中使用缓存的助手类 ///

vs2008ASPNET的专栏 645

AP发票批量付款程序(WEB ADI)

CREATE OR REPLACE PACKAGE MEW_AP_BATCH_PAYMENTS_PKG IS   PROCEDURE MAIN(P_BATCH_ID          NUMBER                 ,P_ORG_ID            NUMBER                 ,P_BANK_ACCOUNT_NAME VARCHAR2

储藏室 5051

【C# 基础精讲】字典(Dictionary)的使用

是C#中非常常用的泛型集合类,用于存储键值对的数据结构。本文介绍了的应用,包括创建字典、添加元素、访问元素、删除元素、遍历字典以及常用的方法。字典是一种高效的数据结构,在需要快速查找和检索数据的场景下特别有用。希望通过本文的介绍,您可以更好地了解和使用,从而在C#编程中更加灵活和高效地处理键值对数据。祝您在C#编程中取得更大的成功!

繁依Fanyi的博客 4万+

Java 网络编程(超级详细)

1. 网络编程 1.1 网络编程概述 计算机网络 是指将地理位置相同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及通信协议的管理和协调下,实现资源共享和信息传递的计算机系统 1.2 网络编程三要素 1、IP地址 要想让网络中的计算机能够互相通信,必须为计算机指定一个标识号,通过这个标识号来指定要接受数据的计算机和识别发送的计算机,而IP地址就是这个标识号,也就是设备的标识。 2、端口 网络的通信,本质上是两个应用程序的通信。每台计算机都有很多的应用程

imByte的博客 3万+

R语言中的Gamma分布函数

在R语言中,我们可以使用最大似然估计(Maximum Likelihood Estimation,MLE)或最小二乘估计(Least Squares Estimation,LSE)等方法来估计Gamma分布的参数。本文介绍了在R语言中使用Gamma分布函数的基本操作,包括生成随机变量、计算概率密度函数和累积分布函数,以及参数估计和拟合。函数来生成Gamma分布的随机变量,计算概率密度函数(PDF)和累积分布函数(CDF),以及进行参数估计和拟合。要计算Gamma分布的累积分布函数(CDF),我们可以使用。

ByteWhiz的博客 1630

c#缓存技术(Dictionary)

无论任何时候,只要传递的参数一致,返回的结果都应该是一致的。这样的函数我们才能够利用缓存。首先我们先定义一个函数,而这个函数将会是我们后面需要缓存的函数: 然后我们修改函数使之能够进行缓存: 这里我们可以看到我们利用了字典来对这个函数进行了缓存。函数首先从字典中判断是否存在参数a的key,如果存在直接返回计算后的结果,如果不存在则计算该结果,并保存到...

diechongming1599的博客 1638

深度解析:C# Modbus TCP协议解析与异常处理(工控上位机必备)

协议解析要精准:掌握MBAP头和PDU的结构,尤其是常用功能码的请求/响应格式,避免因字节处理错误导致通信失败;异常处理要全面:覆盖通信层、协议层、数据层的所有异常类型,针对工业场景制定重试、重连、滤波等策略;资源管理要规范:使用释放资源,采用连接池复用连接,避免端口泄露;工业场景要适配:结合工控现场的特点(网络波动、电磁干扰、设备忙),优化通信效率和数据处理逻辑。通过以上解析和策略,可确保C#上位机与工业设备的Modbus TCP通信具备高稳定性、高可靠性、高容错性,满足工控领域的严苛要求。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 997

C# Dictionary实现缓存

public class CacheHelper { //缓存容器 private static Dictionary<string, object> CacheDictionary = new Dictionary<string, object>(); /// <summary> /// 添加缓存 /// </summary> public st.

weixin_43965881的博客 1119

基于STM32、HAL库的W25Q01JVZEIQ TR FLASH存储器驱动应用程序设计

1Gb (128MB),分为512个可擦除块(block),每个块256KB。:块擦除约30-50ms,芯片擦除约30s。:标准SPI (支持1/2/4线模式)// 初始化CS引脚为高电平。// 擦除扇区(4KB)// 初始化Flash。/* 状态寄存器位 *//* 指令定义 *//* 超时定义 *//* 函数声明 */

corlin6688的博客 267

本地快速部署谷歌开放模型Gemma教程(基于Ollama)

谷歌最近发布了新一代开源AI模型Gemma,此次发布的 Gemma 相比自家的 Gemini 更加轻量级,模型权重也一并开源。不仅可以在笔记本电脑上运行,而且还免费可商用,支持中文。运行速度飞快。

特立独行的博客 6716

C#中:字典Dictionary<Key, Value>的用法

在C#中,Dictionary的主要用途是提供快速的基于键值的元素查找。Dictionary的结构一般是这样的:Dictionary ,它包含在System.Collections.Generic命名空间中。在使用Dictionary前,你必须对它的键类型和值类型进行声明。

qq_42384612的博客 5721

基于OpenCV实现暗通道先验去雾算法及改进,效果惊人

深度技术文,前方高能

公号:一条coding 2万+

c#编程细节(八)上之缓存

缓存概述 各级缓存,分别就是以下各节点 浏览器缓存原理 请求过第一次,就有部分数据缓存在硬盘或内存 DNS&&反向代理 其实原理和浏览器缓存也很相似,都是在请求头,响应头里面进行控制,不过这两个缓存都是面向一群用户的 具体细节比较艰深晦涩,主要还是看服务器缓存和浏览器缓存吧 服务器缓存 ...

MaYang_的博客 519

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

C#中缓存的基本用法总结

本文初步探讨了C#缓存的原理及应用,并以实例加以分析总结,这些对C#初学者来说是很有必要熟练掌握的内容。具体如下: 一、概述: 缓存应用目的:缓存主要是为了提高数据的读取速度。因为服务器和应用客户端之间存在着流量的瓶颈,所以读取大容量数据时,使用缓存来直接为客户端服务,可以减少客户端与服务器端的数据交互,从而大大提高程序的性能。 1、缓存的引用空间:System.Web.Cach

天外有天,人外有人。 专注品质 不断创新 让精益求精成为习惯 1369

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

微信小程序之video

微信小程序之video 一.video组件播放时会出现卡顿:加custom-cache=“{{false}}”属性 二.、1.默认显示封面; 2.一个视频播放的时候,其他视频停止播放,并显示封面。 解决问题思路: 1.通过wx:if判断当前视频是否是播放的状态,如果是就显示视频,如果不是就隐藏视频; 2.点击封面的时候,获取到该视频的id,进行判断,如果当前没有视频播放...

敲门的小白 5229

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

C#中的键和键值对的详解和使用示例

键值对是一种数据结构,用于存储一组由键和与之相关联的值构成的数据项。在C#中,最常见的键值对实现是 Dictionary 类,其中 TKey 表示键的类型,TValue 表示值的类型。键值对的主要特点是键具有唯一性,每个键对应一个值。缓存数据的快速访问存储和管理配置信息实现高效的数据检索和更新总结来说,键和键值对在C#中是非常基础和常用的概念,掌握它们能够帮助开发人员更高效地进行数据操作和管理。

qq_35320456的博客 5909

c# 字典通过key获取value

执行这个方法后,获取的值就直接存放在了row中,后面就可以直接是用了,(如果不清楚C#中out的用法,可以在去了解一下ref和out的用法)dic.TryGetValue(key, out row) //key就是我们已知的关键字,row就是上面我们定义用来存放value的。DataRow row =null //定义一个和value一个的数据类型用来接收获取到的值。主要方法:TryGetValue 方法。2.通过key 获取对应的Value。1.首先定义一个字典。

Pei_hua100的专栏 1637

C# Dictionary->ConcurrentDictionary和哈希表

Dictionary

m0_58717895的博客 2091

C#使用CefSharp之自定义缓存实现

大家好,我是沙漠尽头的狼。上文介绍了《C#使用CefSharp内嵌网页-并给出C#与JS的交互示例》[1],本文介绍CefSharp的缓存实现,先来说说添加缓存的好处:提高页面加载加速:CefSharp缓存可以缓存已经加载过的页面和资源,当用户再次访问相同的页面时,可以直接从缓存中加载,而不需要重新下载和解析页面和资源,从而加快页面加载速度。减少网络流量:使用缓存可以减少网络流量,因为已经下载过的...

farway000的博客 1397

c# 数据结构与算法解读篇(键值对key-value的使用)

key-value的特点: 读取&增删都快? 有 hash散列 字典 key-value,一段连续有限空间放value(开辟的空间比用到的多,hash是用空间换性能),基于key散列计算得到地址索引,这样读取快 增删也快,删除时也是计算位置,增加也不影响别人 肯定会出现2个key(散列冲突),散列结果一致18,可以让第二次的+1, 可能会造成效率的降低,尤其是数据量大的情况下,以...

一点一滴 2万+

C# 中KeyChar和KeyValue的区别

KeyData、KeyCode、KeyValue和KeyChar的区别

被啊奶追着屁股打仍然要编程的浪漫漫画家 1848

C#常见的数据缓存方式详解与实例

C#常见的数据缓存方式详解与实例 除了使用内置和第三方库提供的缓存机制外,还可以自定义缓存实现特定的需求。例如,使用ConcurrentDictionary来创建一个简单的线程安全的缓存。示例// 设置缓存项// 获取缓存项// 使用缓存值// 移除缓存项。

小熊猫 2943

c# dictionary<key,value>用法

要点: 1.任何键都是唯一的 2.值不能为空,值类型是引用类型时可以为空值 3.键key和值value可以为任意类型 Dictionary使用方法: Dictionary<string, string> myDictionary = new Dictionary<string, string>(); 1.添加成员 myDictionary.add("json","17");//当添加同样的键会抛出异常,添加时需要加if判断 myDictionary["Tommy"] = "20"

qq_35947707的博客 5960

C# 键值对 KeyValue 解析

最近看到一个输入字符串或者字节数组解析成键值对的代码,可能对大家有用,简单的写了一下。 当然,你可以用JSON.NET去处理JSON类型的键值对,网上很多资料,就不多说,这里主要说是类似于自定数据格式,类似这样的字符串:string data = "sdada=57.4,aaasd=1234,fdafdsa=3.2,fdsafdsa=3.515,fdsafd=-3.471,gfdasgfd=0.0

SumC Ronnie的博客 2万+
上一篇: TencentOS Server 安装 PostgreSQL
下一篇: docker 与 podman 的故事:一个方兴未艾,一个异军突起
ChaITSimpleLove
ChaITSimpleLove 新星创作者: 编程技术技术领域 新星创作者: 编程技术技术领域
博客等级 码龄9年 7192粉丝 281原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ChaITSimpleLove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值