private void WithHandler(CacheHandlerType type, HandlerPriority priority, CacheHandlerInfo handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            lock (_handlers)
            {
                if (!_handlers.ContainsKey(type))
                {
                    _handlers[type] = new Dictionary <HandlerPriority, ICollection <CacheHandlerInfo> >()
                    {
                        { priority, new List <CacheHandlerInfo> {
                              handler
                          } }
                    };
                }
                else
                {
                    var handlersForType = _handlers[type];

                    if (!handlersForType.ContainsKey(priority))
                    {
                        handlersForType[priority] = new List <CacheHandlerInfo> {
                            handler
                        };
                    }
                    else
                    {
                        handlersForType[priority].Add(handler);
                    }
                }
            }
        }
        public CacheHandlerRegister WithAsyncStoreHandler <TResult>(HandlerPriority priority, Func <CacheStoreContext <TResult>, Task> handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            var handlerInfo = new CacheHandlerInfo
            {
                Handler                 = context => handler((CacheStoreContext <TResult>)context),
                InitialConstructor      = GetOrAddFromCtorCache(CacheHandlerType.Store, handler.GetType(), false, (Func <ICacheContext, object, CacheStoreContext>)((ctx, result) => new CacheStoreContext <TResult>(ctx, TypeHelpers.CheckType <TResult>(result, ctx.SuppressTypeMismatchExceptions)))),
                ContinuationConstructor = GetOrAddFromCtorCache(CacheHandlerType.Store, handler.GetType(), true, (Func <CacheStoreContext, CacheStoreContext>)(ctx => new CacheStoreContext <TResult>(ctx))),
            };

            WithHandler(CacheHandlerType.Store, priority, handlerInfo);

            return(this);
        }
        public CacheHandlerRegister WithAsyncExpiredHandler(HandlerPriority priority, Func <CacheExpiredContext, Task> handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            var handlerInfo = new CacheHandlerInfo
            {
                Handler                 = context => handler((CacheExpiredContext)context),
                InitialConstructor      = GetOrAddFromCtorCache(CacheHandlerType.Expired, handler.GetType(), false, (Func <ICacheContext, RequestValidationResult, IReadOnlyCollection <Uri>, CacheExpiredContext>)((ctx, reason, expiredUris) => new CacheExpiredContext(ctx, reason, expiredUris))),
                ContinuationConstructor = GetOrAddFromCtorCache(CacheHandlerType.Expired, handler.GetType(), true, (Func <CacheExpiredContext, CacheExpiredContext>)(ctx => new CacheExpiredContext(ctx))),
            };

            WithHandler(CacheHandlerType.Expired, priority, handlerInfo);

            return(this);
        }
        public CacheHandlerRegister WithAsyncMissHandler <TResult>(HandlerPriority priority, Func <CacheMissContext <TResult>, Task> handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            var handlerInfo = new CacheHandlerInfo
            {
                Handler                 = context => handler((CacheMissContext <TResult>)context),
                InitialConstructor      = GetOrAddFromCtorCache(CacheHandlerType.Miss, handler.GetType(), false, (Func <ICacheContext, CacheMissContext>)(ctx => new CacheMissContext <TResult>(ctx))),
                ContinuationConstructor = GetOrAddFromCtorCache(CacheHandlerType.Miss, handler.GetType(), true, (Func <CacheMissContext, CacheMissContext>)(ctx => new CacheMissContext <TResult>(ctx))),
            };

            WithHandler(CacheHandlerType.Miss, priority, handlerInfo);

            return(this);
        }