2009-06-09 46 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