/// <summary>
        /// Attempt to return an object from the cache. If the item doesn't
        /// exist or returns an error, call a Func to return the latest
        /// version of an object and insert the result in the cache.
        ///
        /// For most Internet applications, this method is the best method to
        /// call to fetch static data (i.e. images) from the network.
        /// </summary>
        /// <param name="blobCache">The cache to get the item.</param>
        /// <param name="key">The key to associate with the object.</param>
        /// <param name="fetchFunc">A Func which will asynchronously return
        /// the latest value for the object should the cache not contain the
        /// key.
        ///
        /// Observable.Start is the most straightforward way (though not the
        /// most efficient!) to implement this Func.</param>
        /// <param name="absoluteExpiration">An optional expiration date.</param>
        /// <typeparam name="T">The type of item to get.</typeparam>
        /// <returns>A Future result representing the deserialized object from
        /// the cache.</returns>
        public static IObservable <T> GetOrFetchObject <T>(this IBlobCache blobCache, string key, Func <IObservable <T> > fetchFunc, DateTimeOffset?absoluteExpiration = null)
        {
            return(blobCache.GetObject <T>(key).Catch <T, Exception>(_ =>
            {
                var prefixedKey = blobCache.GetHashCode().ToString(CultureInfo.InvariantCulture) + key;

                var result = Observable.Defer(fetchFunc)
                             .Do(x => blobCache.InsertObject(key, x, absoluteExpiration))
                             .Finally(() => _inflightFetchRequests.TryRemove(prefixedKey, out var _))
                             .Multicast(new AsyncSubject <T>()).RefCount();

                return (IObservable <T>)_inflightFetchRequests.GetOrAdd(prefixedKey, result);
            }));
        }
        /// <summary>
        /// Attempt to return an object from the cache. If the item doesn't
        /// exist or returns an error, call a Func to return the latest
        /// version of an object and insert the result in the cache.
        ///
        /// For most Internet applications, this method is the best method to
        /// call to fetch static data (i.e. images) from the network.
        /// </summary>
        /// <param name="key">The key to associate with the object.</param>
        /// <param name="fetchFunc">A Func which will asynchronously return
        /// the latest value for the object should the cache not contain the
        /// key.
        ///
        /// Observable.Start is the most straightforward way (though not the
        /// most efficient!) to implement this Func.</param>
        /// <param name="absoluteExpiration">An optional expiration date.</param>
        /// <returns>A Future result representing the deserialized object from
        /// the cache.</returns>
        public static IObservable <T> GetOrFetchObject <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, DateTimeOffset?absoluteExpiration = null)
        {
            return(This.GetObject <T>(key).Catch <T, Exception>(_ =>
            {
                object dontcare;
                var prefixedKey = This.GetHashCode().ToString() + key;

                var result = Observable.Defer(() => fetchFunc())
                             .Do(x => This.InsertObject(key, x, absoluteExpiration))
                             .Finally(() => inflightFetchRequests.TryRemove(prefixedKey, out dontcare))
                             .Multicast(new AsyncSubject <T>()).RefCount();

                return (IObservable <T>)inflightFetchRequests.GetOrAdd(prefixedKey, result);
            }));
        }