Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.
like image 646
Matthew Avatar asked Mar 18 '23 02:03

Matthew


1 Answers

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;
}
like image 92
Servy Avatar answered Mar 21 '23 08:03

Servy