2009-06-09 75 views
16

任何人都可以解释为什么不能将空对象插入到ASP.NET缓存中吗?ASP.NET无法缓存空值

string exampleItem = null; 

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

异常错误消息指出“值”对象不能为空。在我的应用程序中,我们为什么要在缓存中存储空值是有正当理由的。

回答

17

相关的Cache可能是HashtableDictionary<string, object>,其获取方不区分该关键字没有值或该关键字为空值。

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

+1

字典 *不*区分(这是所有从我的头顶,所以道歉,对任何愚蠢的拼写错误。) null并且没有值。获取不存在的键的值将引发KeyNotFoundException,并存储空值是有效的。 – 2009-06-09 03:12:56

+1

啊。我只测试了Hashtable。更有证据表明Cache基于Hashtable,并具有预插入检查。 – 2009-06-09 03:32:37

+0

派对迟到,但仅供参考,似乎MemoryCache通过返回'null'来传递一个丢失的键。 所以,如果它允许插入空值,它不会知道两者之间的差异。 – GettnDer 2017-09-22 15:34:28

11

为了澄清迈克尔佩特罗塔接受的答案有点(太恐怖了),CacheInternal的具体实现(CacheSingle和CacheMultiple,后者仅管理前者的多个实例),这是公共缓存类型内部使用的以支持其Get,Add,Insert等方法的内存依赖于HashTable进行存储。但是,对于HashTable中的特定键是否存在值,从来没有任何问题,因为本地(缓存)值不直接存储在HashTable中。相反,HashTable充满了包装缓存的键和值的唯一CacheEntry对象(CacheEntry实际上是从CacheKey派生的,添加了一个基于对象的Value属性等等;非空值需求可以在其构造函数中找到)。

根据我对代码的阅读,作者没有明显的技术原因需要非空的CacheEntry.Value,只不过公开的Cache对象不公开Contains或Exists类型的方法,当然不会公开内部底层CacheEntry对象,它只会返回CacheEntry值。因此,根据Michael的回答,在不强迫值非空的情况下,缓存对象用户不可能知道某个特定键值是否存在。这也是可能的,但是需要更多的代码阅读才能确定地知道,在内部采用相当复杂的方法来管理HashTable条目的缓存对象依赖关系,到期日期,事件和就地更新可能会以某种方式依赖于值非空。

8

作为一种可能的选择或解决方法,您可以改为存储一个对象而不是您的值。举例来说(这里假设你的价值是一个字符串,但它可能是通用)

public class CacheItemWrapper 
{ 
    public string Value { get; set; } 
} 

...

cache.Insert(cacheKey, new CacheItemWrapper { Value = null }, ...); 

这样,你永远不会将空。为了得到值回,你刚刚从包装提取它:

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

+0

这很好用我现有的缓存机制,很少修改谢谢。 – Paul 2013-02-07 21:55:26

+1

我已经使用了类似的模式,但只是使用Tuple 作为我的包装;这样我可以让它缓存指定的多种类型的项目,并且不必担心对象本身在空插入到缓存中的情况。 – Rostov 2014-05-13 19:16:07

+0

这是一个很好的解决方法。另一个不错的选择是使用空对象模式,如http://stackoverflow.com/a/9820884/1302581中所述。 – Robertas 2016-08-31 21:52:04