浅谈MemoryCache的原生插值方式
.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);
}
// Don't 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 don't use this entry.
if (_state.IsValueSet)
{
_cache.SetEntry(this);
if (_previous != null && CanPropagateOptions())
{
PropagateOptions(_previous);
}
}
_previous = null; // we don't want to root unnecessary objects
}
}
注意其中的_cache.SetEntry(this),表示在MemoryCache底层的ConcurrentDictionary<object, CacheEntry>集合插入缓存项,
综上:缓存项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语法糖的作用时刻在函数末尾,会带来误导。
浅谈MemoryCache的原生插值方式的更多相关文章
- 浅谈C++三种传参方式
浅谈C++三种传参方式 C++给函数传参中,主要有三种方式:分别是值传递.指针传递和引用传递. 下面通过讲解和实例来说明三种方式的区别. 值传递 我们都知道,在函数定义括号中的参数是形参,是给函数内专 ...
- 【The Most Important】浅谈JSP表单Post方式中文乱码问题
首先祝大家鸡年吉祥!在这里我要说下这两天里这个问题困扰着我,大过年的心情都被烦扰的不好了,所以我带着兴奋的心情来赶快完成这篇博客,解决大家的问题.我的问题是post方式传递表单数据,Tomcat服务器 ...
- 浅谈 Java Xml 底层解析方式
XML 使用DTD(document type definition)文档类型来标记数据和定义数据,格式统一且跨平台和语言,已成为业界公认的标准. 目前 XML 描述数据龙头老大的地位渐渐受到 Jso ...
- 浅谈js模块加载方式(初级)
1.简介: 前端模块化开发日渐鼎盛,如何将零散的插件或者是普通的js脚本文件统一管理及引用,是众多开发者共同的目标.本人是从事.net开发的,最近对前端的一些东西特别的感兴趣,也会尝试的夹杂一点自己 ...
- 浅谈 Java 主流开源类库解析 XML
在大型项目编码推进中,涉及到 XML 解析问题时,大多数程序员都不太会选用底层的解析方式直接编码. 主要存在编码复杂性.难扩展.难复用....,但如果你是 super 程序员或是一个人的项目,也不妨一 ...
- 视频课程 | 云原生下的Serverless浅谈
京东云开发者社区在3月底于北京举行了以"Cloud Native时代的应用之路与开源创新"为主题的技术沙龙,现场多位技术大咖与开发者们面对面就Cloud Native进行了深入交流 ...
- AI云原生浅谈:好未来AI中台实践
AI时代的到来,给企业的底层IT资源的丰富与敏捷提出了更大的挑战,利用阿里云稳定.弹性的GPU云服务器,领先的GPU容器化共享和隔离技术,以及K8S集群管理平台,好未来通过云原生架构实现了对资源的灵活 ...
- 浅谈程序员创业(要有一个自己的网站,最好的方式还是自己定位一个产品,用心把这个产品做好。或者满足不同需求的用户,要有特色)good
浅谈程序员创业 ——作者:邓学彬.Jiesoft 1.什么是创业? 关于“创业”二字有必要重新学习一下,找了两个相对权威定义: 创业就是创业者对自己拥有的资源或通过努力能够拥有的资源进行优化整合,从而 ...
- 【ASP.NET MVC系列】浅谈ASP.NET 页面之间传值的几种方式
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
随机推荐
- day13 iptables防火墙
day13 iptables防火墙 一.防火墙的概述 1.什么是防火墙 防止恶意流量访问的软件就叫做防火墙. 2.防火墙的种类 软件防火墙:firewalld.iptables 硬件防火墙:F5 fi ...
- Docker快速上手入门
Docker 什么是Docker? Docker就是一种虚拟化的技术 可以通过Docker快速的下载使用第三方技术,方便搭建环境 目的:Securely build,share and run any ...
- Git配置文件与git config命令
在Git配置文件中配置变量,可以控制Git的外观和操作的各个方面.通过git config命令可以获得和设置配置变量. 一.Git配置文件的位置 这些变量可以被存储在三个不同的位置: 1./etc/g ...
- When should we write our own assignment operator in C++?
The answer is same as Copy Constructor. If a class doesn't contain pointers, then there is no need t ...
- 【Java 基础】java 创建对象时重写方法
TransactionLock mockLock = new TransactionLock() { public boolean lock(String id) { return true; } p ...
- RestTemplate进行访问分页PageInfo
废话少说,给你们看代码: //provide的controller @ResponseBody @RequestMapping(value = "details",method = ...
- Controller返回类的自动识别,WEB-INF,jsp位置
Controller: @Controller@RequestMapping("/params")public class ParamsController { @RequestM ...
- 如何使用table布局静态网页
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 【力扣】有序矩阵中第K小的元素
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素.请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素. 示例: matrix = [ [ 1, 5, ...
- 计算机网络 Raw_Socket编程 Ping C语言
计算机网络做了一个附加题,用C语言Raw_Socket实现ping指令. 通过本部的Mooc学习了一下Socket编程,然后成功写了出来orz 先放一下代码: #include <stdio.h ...