/// <summary>
        /// Retrieves the object by the specified key from the cache.  If the object does not exist in the cache, it will be added.
        /// </summary>
        /// <typeparam name="T">Type of object to return</typeparam>
        /// <param name="cache">Cache to work with</param>
        /// <param name="key">Cache key for the object</param>
        /// <param name="cacheAction">Action to perform if the object does not exist in the cache.</param>
        /// <returns></returns>
        public static T GetOrCache <T>(this ICacheClient cache, string key, Func <ICacheContext, T> cacheAction) where T : class
        {
            var item      = cache.Get <T>(key);
            var eventArgs = new CacheHitEventArgs
            {
                CacheKey = key,
                Type     = typeof(T)
            };

            if (item == null)
            {
                CacheStackSettings.OnCacheMiss(cache, eventArgs);
                var context = new CacheContext(cache);

                item = cacheAction(context);

                // No need to cache null values
                if (item != null)
                {
                    cache.CacheAndSetTriggers(context, key, item);
                }
            }
            else
            {
                CacheStackSettings.OnCacheHit(cache, eventArgs);
            }
            return(item);
        }
        /// <summary>
        /// Retrieves the object by the specified key from the cache.  If the object does not exist in the cache, it will be added.
        /// </summary>
        /// <typeparam name="T">Type of object to return</typeparam>
        /// <param name="cache">Cache to work with</param>
        /// <param name="key">Cache key for the object</param>
        /// <param name="cacheAction">Action to perform if the object does not exist in the cache.</param>
        /// <returns></returns>
        public static T GetOrCacheStruct <T>(this ICacheClient cache, string key, Func <ICacheContext, T> cacheAction) where T : struct
        {
            // Wrap the value type as nullable and check the cache
            var item = cache.Get <T?>(key);

            if (item == null)
            {
                var context = new CacheContext(cache);

                item = cacheAction(context);
                cache.CacheAndSetTriggers(context, key, item);
            }
            return(item.Value);
        }