You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不更改过期时间的情况下更新IMemoryCache中的值类型?

解决IMemoryCache存储int值无法持久化更新的问题

这个问题我太熟了!你猜的完全没错——就是值类型的特性在IMemoryCache里搞出的麻烦。

问题根源

IMemoryCache本质是基于对象存储的,当你把int这种值类型存进去时,CLR会自动把它装箱成object。等你从缓存里取出这个值时,得到的是装箱对象的值副本(值类型的赋值都是按值传递的)。所以你修改这个副本的数值,根本不会影响缓存里原来那个装箱后的对象,自然看不到更新效果。至于加ref关键字没用,是因为ref只是在方法调用时传递变量的引用,但你从缓存取出的过程已经完成了值拷贝,ref也救不了这个问题。

解决方案

方案一:用自定义引用类型包装int(最推荐)

写一个简单的包装类,把int包在里面,这样存进缓存的就是引用类型了,修改的时候直接操作引用指向的对象,自然就能持久化:

// 定义包装类
public class IntHolder
{
    public int Value { get; set; }
}

// 初始化缓存
_memoryCache.Set("UserCount", new IntHolder { Value = 0 });

// 更新值
var holder = _memoryCache.Get<IntHolder>("UserCount");
if (holder != null)
{
    holder.Value++; // 这里修改的是缓存里对象的实际值
}

这个方法逻辑清晰,更新时不需要重新写入整个缓存,性能也更好,适合大多数场景。

方案二:每次更新直接重新Set缓存

如果不想写额外的类,也可以每次更新时先取出当前值,计算新值后重新存入缓存:

// 获取当前值(不存在则默认0)
var currentCount = _memoryCache.Get<int?>("UserCount") ?? 0;
// 存入新值
_memoryCache.Set("UserCount", currentCount + 1);

这个方法简单直接,但要注意并发场景下可能出现竞态条件(比如两个请求同时取到相同的currentCount,导致最终计数少加了)。如果需要并发安全,可以结合Interlocked来处理:

// 并发安全的写法
var currentCount = _memoryCache.Get<int?>("UserCount") ?? 0;
var newCount = Interlocked.Increment(ref currentCount);
_memoryCache.Set("UserCount", newCount);

方案三:用现成的引用类型“凑数”

如果你嫌写包装类麻烦,也可以用.NET自带的引用类型来装int,比如List<int>(虽然有点大材小用,但胜在快捷):

// 初始化
_memoryCache.Set("UserCount", new List<int> { 0 });

// 更新
var countList = _memoryCache.Get<List<int>>("UserCount");
if (countList != null)
{
    countList[0]++;
}

这个方法不用写额外代码,但可读性不如自定义包装类,适合快速测试或者简单场景。

总结

核心就是避开值类型的装箱副本问题,要么用引用类型包裹,要么每次更新时重新覆盖缓存值。根据你的场景选最顺手的就行~

内容的提问来源于stack exchange,提问作者user3953989

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:12:51