Search code examples
c#.netlazy-evaluationmemorycache

How should I populate a MemoryCache without instantiating the object to be cached unneccesarily?


The MemoryCache class exposes a method called .AddOrGetExisting which is a threadsafe way to get if exists, and add if it doesn't exist.

This method returns NULL if the cached object didn't already exist. I think I understand the value of this because it provides feedback to the user regarding its existence in the cache.

My cache resolver looks like this:

private static T GetCachedCollection<T>(Guid cacheKey, Lazy<T> initializer)
{
    return (T) (MemoryCache.Default.AddOrGetExisting(cacheKey.ToString(), initializer.Value, _policy) ?? initializer.Value);
}

What I am trying to accomplish is that the object is not created unless it is needed, and if it is needed I don't want to construct it twice.

The concern I have is that when I pass the .Value of my Lazy type as a parameter it may invoke the initializer regardless of whether the item is found in cache or not. However, if I understand JIT properly it will pass the delegate of the method and not invoke it.

How should I accomplish these goals:

  1. Do not invoke the object initializer if it already exists in cache
  2. If it is not in the cache then invoke it only one time.

Solution

  • Don't store the object in the cache, store the Lazy.

    private static T GetCachedCollection<T>(Guid cacheKey, Lazy<T> initializer)
    {
        var cachedValue = (Lazy<T>)(MemoryCache.Default.AddOrGetExisting(
            cacheKey.ToString(), initializer, _policy) ?? initializer);
        return cachedValue.Value;
    }