C# ASP.NET 无法缓存空值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/967893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:27:19  来源:igfitidea点击:

ASP.NET can't cache null value

c#asp.netcaching

提问by Kane

Can anyone explain why you cannot insert a null object into the ASP.NET cache?

谁能解释为什么不能将空对象插入 ASP.NET 缓存?

string exampleItem = null;

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

The exception error message states that the "value" object cannot be null. In my application there are valid reasons why we whould want to store a null value in the cache.

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

采纳答案by Michael Petrotta

Underlying Cacheis likely a Hashtableor Dictionary<string, object>, whose getters do not differentiate between no value at that key, or a null value at that key.

底层Cache可能是 a Hashtableor 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'

Consider a using placeholder "null" item, similar to DbNull.Value.

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

回答by ewbi

To clarify Michael Petrotta's accepted answer a bit (too long for a comment, I'm afraid), the concrete implementations of CacheInternal (CacheSingle and CacheMultiple, the latter of which merely manages multiple instances of the former), which is what's utilized internally by the public Cache type to support its Get, Add, Insert, etc. methods, do rely on a HashTable for storage. However, there's never any question of whether there is or isn't a value for a particular key in the HashTable, because the native (cached) values aren't stored in the HashTable directly. Instead, the HashTable is filled with unique CacheEntry objects that wrap the cached keys and values (CacheEntry actually derives from CacheKey, adding an Object-based Value property, among other things; the non-null value requirement can be found in its constructor).

为了澄清 Michael Petrotta 接受的答案(恐怕评论太长了),CacheInternal(CacheSingle 和 CacheMultiple,后者仅管理前者的多个实例)的具体实现,这是内部使用的public Cache类型支持其Get、Add、Insert等方法,确实依赖一个HashTable进行存储。但是,对于 HashTable 中的特定键是否存在值,从来没有任何问题,因为本机(缓存)值不直接存储在 HashTable 中。相反,HashTable 填充了唯一的 CacheEntry 对象,这些对象包装了缓存的键和值(CacheEntry 实际上是从 CacheKey 派生的,添加了一个基于对象的 Value 属性等等;

Based on my reading of the code, there's no obvious technical reason for the authors to have required a non-null CacheEntry.Value, except that the public Cache object doesn't expose a Contains- or Exists-type method, and of course doesn't expose the internal underlying CacheEntry objects, it only returns the CacheEntry values. So, as per Michael's answer, without forcing values to be non-null it isn't possible for Cache object users to know whether a particular key value exists. It's also possible, but would require more code reading to know for sure, that the rather complex approach taken internally to manage cached object dependencies, expirations, events, and in-place updates of HashTable entries might rely, in some way, on the values being non-null.

根据我对代码的阅读,作者没有明显的技术原因需要一个非空的 CacheEntry.Value,除了公共 Cache 对象没有公开一个 Contains- 或 Exists-type 方法,当然也没有不公开内部底层 CacheEntry 对象,它只返回 CacheEntry 值。因此,根据迈克尔的回答,如果不强制值非空,缓存对象用户不可能知道特定键值是否存在。这也是可能的,但需要更多的代码阅读才能确定,内部采用的相当复杂的方法来管理缓存对象依赖项、到期、事件和 HashTable 条目的就地更新可能在某种程度上依赖于这些值非空。

回答by Steve Owen

As a possible alternative or work-around, you can instead store an object rather than your value. For instance (this assumes your value is a string, but it could be generic)

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

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

...

...

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

That way you are never inserting null. To get the value back, you just extract it from the wrapper:

这样你就永远不会插入空值。要取回值,您只需从包装器中提取它:

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

(This is all off the top of my head, so apologies for any silly typos.)

(这完全超出了我的脑海,所以为任何愚蠢的错别字道歉。)