C# ASP.NET可以';t缓存空值

C# ASP.NET可以';t缓存空值,c#,asp.net,caching,C#,Asp.net,Caching,有人能解释为什么不能将空对象插入ASP.NET缓存吗 string exampleItem = null; HttpRuntime.Cache.Insert("EXAMPLE_KEY", exampleItem, Nothing, DateTime.Now.AddHours(1),

有人能解释为什么不能将空对象插入ASP.NET缓存吗

string exampleItem = null;

HttpRuntime.Cache.Insert("EXAMPLE_KEY", 
                        exampleItem, 
                        Nothing,                           
                        DateTime.Now.AddHours(1),
                        System.Web.Caching.Cache.NoSlidingExpiration);

异常错误消息声明“value”对象不能为null。在我的应用程序中,我们希望在缓存中存储空值是有充分理由的。

底层
缓存
可能是一个
哈希表
字典
,其getter不区分该键上的无值或该键上的空值

Hashtable table = new Hashtable();
object x = table["foo"];
table.Add("foo", null);
object y = table["foo"];
Console.WriteLine(x == y); // prints 'True'

考虑使用占位符“null”项,类似于
DbNull.Value

,以澄清Michael Petrotta接受的答案(恐怕太长,无法评论),CacheInternal的具体实现(CacheSingle和CacheMultiple,后者仅管理前者的多个实例),这是公共缓存类型内部用来支持其Get、Add、Insert等方法的内容。方法确实依赖于哈希表进行存储。但是,哈希表中是否存在特定键的值这一问题从来都不存在,因为本机(缓存)值不会直接存储在哈希表中。相反,哈希表中填充了包装缓存键和值的唯一CacheEntry对象(CacheEntry实际上是从CacheKey派生的,添加了基于对象的值属性等;非空值要求可以在其构造函数中找到)


根据我对代码的阅读,作者没有明显的技术理由要求使用非null CacheEntry.Value,除了公共缓存对象不公开包含或存在类型的方法,当然也不公开内部基础CacheEntry对象之外,它只返回CacheEntry值。因此,根据Michael的回答,如果不强制值为非null,缓存对象用户就不可能知道是否存在特定的键值。这也是可能的,但需要更多的代码阅读才能确定,内部用于管理缓存对象依赖项、过期、事件和哈希表项的就地更新的相当复杂的方法可能在某种程度上依赖于非空值。

作为可能的替代方法或解决方法,您可以改为存储对象而不是值。例如(这假设您的值是一个字符串,但它可以是泛型的)

这样,就永远不会插入null。要恢复该值,只需从包装器中提取它:

var val = cache.Get(cacheKey);
if (val != null) return val.Value;

(这完全是我的想法,所以为所有愚蠢的打字错误道歉。)

字典确实区分空值和无值。获取不存在的键的值会抛出KeyNotFoundException,而存储空值是有效的。啊。我只测试了Hashtable。更多的证据表明,缓存是基于哈希表的,并带有预插入检查。虽然时间较晚,但只是为了提供信息,MemoryCache似乎通过返回“null”来传递缺少的密钥。因此,如果它允许插入空值,它将不知道两者之间的区别。这对我现有的缓存机制非常有效,只需稍加修改,谢谢。我使用了类似的模式,但只使用了一个元组作为包装器;这样,我就可以让它按照指定的方式缓存多种类型的项,而不必担心对象本身会在空插入到缓存中时出错,这是一个很好的解决方法。另一个不错的选择是使用空对象模式,如下所述。
cache.Insert(cacheKey, new CacheItemWrapper { Value = null }, ...);
var val = cache.Get(cacheKey);
if (val != null) return val.Value;