MemoryCache 的原生插值方式淺談
導讀 | 這在Github上也有issue討論,從2017年開始就有大佬質疑這是一個反人類的設計思路,官方為了不引入Break Change,一直保持到現在。 |
.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(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
綜上:快取項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時,快取項其實還沒插入!!!
MemoryCache插值的實現過程很奇葩
儘量使用帶明確大括號範圍的using語法,C#8.0推出的不帶大括號的using語法糖的作用時刻在函式末尾,會帶來誤導。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2852454/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺談ddos的測試方式
- AOP的姿勢之 簡化 MemoryCache 使用方式
- 淺談熱補丁的鉤取方式
- SCSS #{} 插值CSS
- 淺談非同步呼叫幾種方式非同步
- MATLAB一維插值和二維插值 比較Matlab
- 二、插值操作
- 淺談Python變數賦值的三種方法!Python變數賦值
- 九種常見二維插值方法及雙線性插值的理解
- IPv6升級有幾種方式?淺談淺談IPv6改造方案
- 求插值係數
- 插值技術研究
- c#-string 插值C#
- 【java】【插值查詢】Java
- 再談屬性動畫——介紹以及自定義Interpolator插值器動畫
- 淺談HTTP中GET和POST請求方式的區別HTTP
- 淺談Analysis Services MDX中父子維的實現方式UXUX
- 插值查詢的簡單理解
- Vuex與Busemit結合使用淺談Vuex使用方式VueMIT
- 淺談工業生產裝置採集方式
- 拉格朗日插值
- B樣條插值加速
- 淺談 SAP ABAP 系統裡的 ALV 輸出方式實現
- 牛火火:淺談大資料的價值與影響大資料
- 淺淺談ReduxRedux
- 洛谷P4781 【模板】拉格朗日插值(拉格朗日插值)
- 淺談 [NOIP 2023]三值邏輯 無限種解法
- Swift 5 字串插值之美Swift字串
- scala實現球面插值(Slerp)
- 2.Vue插值表示式Vue
- 插值查詢演算法演算法
- Swift 5 字串插值-簡介Swift字串
- webgl centroid質心插值的一點理解Web
- HashMap 連結串列插入方式 → 頭插為何改成尾插 ?HashMap
- 淺談JavaScript中的thisJavaScript
- 淺淺淺談JavaScript作用域JavaScript
- vue.js插值與表示式Vue.js
- mapboxgl 中插值表示式的應用場景