ASP.NET无法缓存空值

Kan*_*ane 20 c# asp.net caching

任何人都可以解释为什么你不能将空对象插入ASP.NET缓存?

string exampleItem = null;

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

异常错误消息指出"value"对象不能为null.在我的应用程序中,有充分的理由说明为什么我们想要在缓存中存储空值.

Mic*_*tta 20

底层Cache可能是a Hashtable或者Dictionary<string, object>,其getter不区分该键的值,或该键的空值.

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

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

  • Dictionary&lt;T,K&gt; *确实* 区分空值和无值。获取不存在的键的值会引发 KeyNotFoundException,并且存储空值是有效的。 (2认同)
  • 虽然迟到了,但仅供参考,MemoryCache 似乎通过返回“null”来传达丢失的密钥。因此,如果它允许插入空值,它就不会知道两者之间的区别。 (2认同)

Ste*_*wen 12

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

public class CacheItemWrapper
{
    public string Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

...

cache.Insert(cacheKey, new CacheItemWrapper { Value = null }, ...);
Run Code Online (Sandbox Code Playgroud)

这样你永远不会插入null.要获取值,只需从包装器中提取它:

var val = cache.Get(cacheKey);
if (val != null) return val.Value;
Run Code Online (Sandbox Code Playgroud)

(这一切都是我的头脑,所以对任何愚蠢的错别道歉.)

  • 我使用了类似的模式,但只是使用了 Tuple&lt;T&gt; 作为我的包装器;这样我就可以让它缓存指定的多种类型的项目,而不必担心对象本身在将空插入到缓存中时会吐出来 (2认同)

ewb*_*wbi 11

为了澄清迈克尔Petrotta的接受的答案有点(太长的评论,我怕),CacheInternal(CacheSingle和CacheMultiple,其中仅管理前的多个实例后),这是什么通过内部使用的具体实现公共Cache类型支持其Get,Add,Insert等方法,确实依赖HashTable进行存储.但是,HashTable中的特定键是否存在或不存在任何问题,因为本机(缓存)值不会直接存储在HashTable中.相反,Hashtable是充满了包缓存键和值独特CacheEntry对象(CacheEntry实际上是从CacheKey派生,添加一个基于对象的Value属性,除其他事项外,在非空值的要求可以在构造函数中找到).

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