ASP.NET не может кэшировать нулевое значение

Может ли кто-нибудь объяснить, почему вы не можете вставить нулевой объект в кеш ASP.NET?

string exampleItem = null;

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

Сообщение об ошибке указывает, что объект "значение" не может быть нулевым. В моем приложении есть веские причины, по которым мы хотим сохранить нулевое значение в кеше.

Ответы

Ответ 1

Базовое Cache, скорее всего, Hashtable или Dictionary<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.

Ответ 2

Чтобы разъяснить, что Майкл Петротта принял ответ немного (слишком долго для комментария, я боюсь), конкретные реализации CacheInternal (CacheSingle и CacheMultiple, последний из которых просто управляет несколькими экземплярами первого), что и есть используемый внутри общего типа Cache для поддержки его методов Get, Add, Insert и т.д., полагайтесь на HashTable для хранения. Однако никогда не возникает вопроса о том, существует или нет значение для конкретного ключа в HashTable, поскольку собственные (кэшированные) значения не хранятся непосредственно в HashTable. Вместо этого, HashTable заполняется уникальными объектами CacheEntry, которые обертывают кешированные ключи и значения (CacheEntry на самом деле происходит от CacheKey, добавив, помимо прочего, свойство Value на основе Object, требование по ненулевому значению можно найти в его конструкторе).

Основываясь на моем чтении кода, нет очевидной технической причины для того, чтобы авторы потребовали ненулевой CacheEntry.Value, за исключением того, что публичный объект Cache не предоставляет метод Contains- или Exists-type и конечно, не раскрывает внутренние базовые объекты CacheEntry, он возвращает только значения CacheEntry. Таким образом, согласно ответам Майкла, не заставляя значения быть ненулевыми, пользователям объекта Cache не удается узнать, существует ли конкретное значение ключа. Это также возможно, но для этого потребуется больше кода, чтобы точно знать, что довольно сложный подход, используемый внутренне для управления зависимостями кэшированных объектов, истечениями, событиями и обновлениями на месте записей HashTable, может каким-то образом опираться на значения не имеет значения.

Ответ 3

В качестве возможной альтернативы или работы вы можете вместо этого сохранить объект, а не свое значение. Например (это предполагает, что ваше значение является строкой, но оно может быть общим)

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;

(Это все с головы доски, поэтому приношу извинения за любые глупые опечатки.)