public bool Handle(CacheAccess access, TKey key, ref TValue value, bool isGetOrPut)
        {
            bool found = ContainsKey(key);

            if (!found || isGetOrPut)
            {
                if (!found && access == CacheAccess.Get)
                {
                    // Failure; can't Get (key not found)
                    return(false);
                }
                if (TracksChanges())
                {
                    Before(access, key, value);
                }
                try
                {
                    var onAccess =
                        Policy != null ?
                        access == CacheAccess.Get ? Policy.OnGet :
                        access == CacheAccess.Set ? isGetOrPut ? Policy.OnPut : Policy.OnAdd : null : null;
                    if (access == CacheAccess.Get)
                    {
                        // It's a Get
                        value = this[key];
                    }
                    else
                    {
                        if (!isGetOrPut)
                        {
                            // It's an Add
                            Add(key, value);
                        }
                        else
                        {
                            // It's a Put
                            this[key] = value;
                        }
                    }
                    switch (access)
                    {
                    case CacheAccess.Get:
                    // It's a cache hit, so give the policy a chance
                    // to mutate the data if so desired (via onAccess)
                    // e.g., for the sake of reordering the evictables
                    // as a side-effect of the cache hit
                    // (cf. next comment in "finally{...}" clause below)
                    case CacheAccess.Set:
                        if (onAccess != null)
                        {
                            onAccess(Source, key, value);
                        }
                        break;

                    default:
                        throw new NotSupportedException(access.ToString());
                    }
                }
                finally
                {
                    if (TracksChanges())
                    {
                        // Keep our own internal state consistent
                        // even if the policy happens to fail;
                        // the following is to keep the evictable
                        // key/value pairs in order;
                        // note that in the special case of LRU/MRU
                        // evictions, it's the passing of time
                        // that defines the order
                        // (see FifoCacheEviction<TKey, TValue>)
                        After(access, key, value);
                    }
                }
                // Success; could Get, Add, or Put
                return(true);
            }
            // Failure; can't Add (key already in use)
            return(false);
        }