当前位置: 首页 > 科技观察

浅谈MemoryCache的原生插值方法

时间:2023-03-19 00:11:23 科技观察

.NET运行时内置了一个公共缓存模块:MemoryCache标准的MemoryCache暴露了如下属性和方法:publicintCount{get;}publicvoidCompact(doublepercentage);publicICacheEntryCreateEntry(objectkey);publicvoidDispose();publicvoidRemove(objectkey);publicboolTryGetValue(objectkey,outobjectresult);protectedvirtualvoidDispose(boolddisposing);但是如果使用普通模式插值/取值,可能会出现意想不到的情况。像这样的常规代码:vars=newMemoryCache(newMemoryCacheOptions{});varentry=s.CreateEntry("WeChatID");entry.Value="LeanCoder";varf=s.TryGetValue("WeChatID",outobjectobj);控制台.WriteLine(f);控制台.WriteLine(obj);会输出如下结果:是不是很奇怪。但是观察者一般不会使用MemoryCache的原生方法,而是使用位于同一个命名空间的扩展方法Set。vars=newMemoryCache(newMemoryCacheOptions{});s.Set("WeChatID","精益码农");varf=s.TryGetValue("WeChatID",outobjectobj);Console.WriteLine(f);Console.WriteLine(obj);这将正确输出。看一下扩展类的源代码扩展方法和native方法的区别在于using关键字(也解释了CacheEntry继承自IDisposable接口)。继续追踪CacheEntry实现的Dispose方法:publicvoidDispose(){if(!_state.IsDisposed){_state.IsDisposed=true;if(_cache.TrackLinkedCacheEntries){CacheEntryHelper.ExitScope(this,_previous);}//Don'tcommitorpropagateoptionsiftheCacheEntryValue/wasneverset。/WeassumeanexceptionoccurredcausingthecallertonotsettheValuesuccessfully,//sodon'tusethisentry.if(_state.IsValueSet){_cache.SetEntry(this);if(_previous!=null&&CanPropagateOptions()){PropagateOptions(_previous);}}_previous=null;注意_cache.SetEntry(this)表示它在MemoryCache底部的ConcurrentDictionary中。总结:缓存项CacheEntry需要先Disposed,才能插入到MemoeyCache中。这是一种什么样的设计模式?IDisposable接口不是用来释放资源的吗?为什么要使用Dispose方法插值到MemoryCache中?不能使用显式的Commit方法吗?这也是Github上的一个issue讨论,从2017年开始就有boss质疑这是反人类的设计思路。为了不引入BreakChange,官方一直保留到现在。基于这种情况,如果我们使用MemoryCache的原生插值方式,我们需要这样:";}varf=s.TryGetValue("WeChatID",outobjectobj);...尽量不要使用C#8.0引入的不带花括号的using语法usingvarentry=s.CreateEntry("WeChatID");entry.Value="Lean码农";varf=s.TryGetValue("WeChatID",outobjectobj);...这种没有明确指定使用范围的语法会在函数最后执行Dispose方法,导致执行TryGetValue时缓存项还没有插入!!!LastMemoryCache插值的实现过程很奇怪。尝试使用带有大括号的using语法。C#8.0引入的不带大括号的using语法糖总是在函数的末尾,这会产生误导。