.NET 7中MemoryCache获取EntriesCollection属性返回null的解决方法
问题描述
我有一段在.NET 6环境下运行正常的代码,升级至.NET 7后无法正常工作。核心问题是typeof(MemoryCache).GetProperty("EntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance)始终返回null。原代码如下:
// Get the empty definition for the EntriesCollection var cacheEntriesCollectionDefinition = typeof(MemoryCache).GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (cacheEntriesCollectionDefinition!=null) { // Populate the definition with your IMemoryCache instance. // It needs to be cast as a dynamic, otherwise you can't // loop through it due to it being a collection of objects. var cacheEntriesCollection = cacheEntriesCollectionDefinition.GetValue(_cache) as dynamic; if (cacheEntriesCollection!=null) { // Define a new list we'll be adding the cache entries too List<ICacheEntry> cacheCollectionValues = new List<ICacheEntry>(); foreach (var cacheItem in cacheEntriesCollection) { // Get the "Value" from the key/value pair which contains the cache entry ICacheEntry cacheItemValue = cacheItem.GetType().GetProperty("Value").GetValue(cacheItem, null); // Add the cache entry to the list cacheCollectionValues.Add(cacheItemValue); } var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); var keysToRemove = cacheCollectionValues.Where(d => regex.IsMatch(d.Key.ToString())).Select(d => d.Key).ToList(); foreach (var key in keysToRemove) { _cache.Remove(key); } } }
修复方案
.NET 7对MemoryCache的内部实现做了调整,移除了原有的EntriesCollection私有属性,改用_entries私有字段存储缓存条目集合。你需要修改反射逻辑,从获取属性改为获取字段,再直接处理内部的字典结构:
using System.Reflection; using System.Text.RegularExpressions; using Microsoft.Extensions.Caching.Memory; // 获取MemoryCache内部的_entries私有字段 var entriesField = typeof(MemoryCache).GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance); if (entriesField != null) { // _entries的实际类型是ConcurrentDictionary<object, CacheEntry>,这里先转为通用字典类型 var entries = entriesField.GetValue(_cache) as System.Collections.Concurrent.ConcurrentDictionary<object, object>; if (entries != null) { var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); // 直接遍历字典的键,匹配后收集需要删除的键 var keysToRemove = entries.Keys.Where(key => regex.IsMatch(key.ToString())).ToList(); foreach (var key in keysToRemove) { _cache.Remove(key); } } }
重要提示
- 依赖私有成员的反射实现不具备长期兼容性,微软可能在后续.NET版本中再次修改内部结构,导致代码失效。
- 推荐的替代方案是在添加缓存时自行维护缓存键的集合(比如用
ConcurrentHashSet或ConcurrentDictionary),清理时直接遍历这个集合,完全避免反射操作,这样代码更稳定可靠。
内容的提问来源于stack exchange,提问作者volkan topal
相关产品推荐
相关产品推荐

