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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺談iOS常用的幾種傳值方式iOS
- 淺談ddos的測試方式
- 淺談ES6原生PromisePromise
- 淺談CSRF攻擊方式
- SCSS #{} 插值CSS
- 淺談熱補丁的鉤取方式
- 二、插值操作
- MATLAB插值Matlab
- 淺談非同步呼叫幾種方式非同步
- MATLAB一維插值和二維插值 比較Matlab
- 伺服器遷移的兩種方式淺談伺服器
- 【java】【插值查詢】Java
- 求插值係數
- 插值技術研究
- 淺談 block(2) – 截獲變數方式BloC變數
- 淺談貝貝遊戲資料加密解密方式遊戲加密解密
- 插值查詢的簡單理解
- 淺談Jquery中的bind(),live(),delegate(),on()繫結事件方式jQuery事件
- 淺談Python變數賦值的三種方法!Python變數賦值
- IPv6升級有幾種方式?淺談淺談IPv6改造方案
- Windows程式間各種通訊方式淺談Windows
- 數值計算 插值與擬合
- c#-string 插值C#
- 拉格朗日插值
- 再談屬性動畫——介紹以及自定義Interpolator插值器動畫
- 淺談Analysis Services MDX中父子維的實現方式UXUX
- 淺談HTTP中GET和POST請求方式的區別HTTP
- 淺談工業生產裝置採集方式
- Vuex與Busemit結合使用淺談Vuex使用方式VueMIT
- [原創]淺談測試環境管理方式
- 淺談索引序列之是否可以儲存NULL值?索引Null
- 插值查詢演算法演算法
- Swift 5 字串插值之美Swift字串
- Swift 5 字串插值-簡介Swift字串
- 插值演算法總結演算法
- CoffeeScript攻略3.8:字串插值字串
- 2.Vue插值表示式Vue
- 遊戲中的經濟:淺談貨幣在遊戲中的價值遊戲