您现在的位置是:亿华云 > 数据库

浅谈 MemoryCache 的原生插值方式

亿华云2025-10-03 02:06:03【数据库】1人已围观

简介.NET运行时内置了常用的缓存模块:MemoryCache标准的MemoryCache暴露了如下几个属性和方法:publicintCount{get;}publicvoidCompact(double

.NET运行时内置了常用的浅谈缓存模块:MemoryCache

标准的MemoryCache暴露了如下几个属性和方法:

public int Count {  get; } public void Compact(double percentage); public ICacheEntry CreateEntry(object key); public void Dispose(); public void Remove(object key); public bool TryGetValue(object key, out object result); protected virtual void Dispose(bool disposing); 

但是你使用常规模式去插值/获取值,可能会出现意想不到的原生情况。

就如下这样的插值常规代码:

var s = new MemoryCache(new MemoryCacheOptions {  }); var entry = s.CreateEntry("WeChatID"); entry.Value = "精益码农"; var f =  s.TryGetValue("WeChatID",out  object obj); Console.WriteLine(f); Console.WriteLine(obj); 

会输出如下结果:

是不是很意外。

但是浅谈看官们一般不会使用MemoryCache的原生方法,而是原生使用位于同一命名空间的 扩展方法Set。

var s = new MemoryCache(new MemoryCacheOptions {  }); s.Set("WeChatID",插值 "精益码农"); var f = s.TryGetValue("WeChatID", out object obj); Console.WriteLine(f); Console.WriteLine(obj); 

如此便能正确输出。

扩展类源码看一看

public static TItem Set<TItem>(this IMemoryCache cache,浅谈 object key, TItem value) {       using ICacheEntry entry = cache.CreateEntry(key);      entry.Value = value;      return value; 

扩展方法与原生方法的云服务器差异在于using关键字 (也说明了CacheEntry继承自IDisposable接口)。

继续追溯CacheEntry实现的原生Dispose方法:

public void Dispose()  {       if (!_state.IsDisposed)      {           _state.IsDisposed = true;          if (_cache.TrackLinkedCacheEntries)          {               CacheEntryHelper.ExitScope(this, _previous);          }          // Dont commit or propagate options if the CacheEntry Value was never set.          // We assume an exception occurred causing the caller to not set the Value successfully,          // so dont use this entry.          if (_state.IsValueSet)          {               _cache.SetEntry(this);              if (_previous != null && CanPropagateOptions())              {                   PropagateOptions(_previous);              }          }          _previous = null; // we dont want to root unnecessary objects      }  } 

注意其中的_cache.SetEntry(this),表示在MemoryCache底层的插值ConcurrentDictionary

综上:缓存项CacheEntry需要被Dispose,才能被插入MemoeyCache。浅谈

这是原生怎样的设计模式?IDisposable接口不是用来释放资源吗?

为啥要使用Dispose方法来向MemoryCache插值?

不能使用一个明确的Commit方法吗?

这在Github上也有issue讨论,从2017年开始就有大佬质疑这是插值一个反人类的设计思路,官方为了不引入Break Change,浅谈一直保持到现在。服务器托管原生

基于此现状,插值我们如果使用MemoryCache的原生插值方法, 需要这样:

var s = new MemoryCache(new MemoryCacheOptions {  }); using (var entry = s.CreateEntry("WeChatID")) {       entry.Value = "精益码农"; } var f = s.TryGetValue("WeChatID", out object obj); ... 

尽量不要使用C#8.0推出的不带大括号的using语法

using var entry = s.CreateEntry("WeChatID"); entry.Value = "精益码农"; var f = s.TryGetValue("WeChatID", out object obj); ... 

这种没明确指定using作用范围的语法,会在函数末尾才执行Dispose方法, 导致执行到TryGetValue时,缓存项其实还没插入!!!

Last

MemoryCache插值的实现过程很奇葩 尽量使用带明确大括号范围的using语法,C#8.0推出的不带大括号的using语法糖的作用时刻在函数末尾,会带来误导。源码下载

很赞哦!(95768)