private CacheResultInfo GetCacheResultInfo(MethodInfo method)
        {
            CacheResultInfo cacheResultInfo = (CacheResultInfo)_cacheResultAttributeCache[method];
            // no need for locking here - last one wins
            if (cacheResultInfo == null)
            {
                CacheResultAttribute resultInfo = (CacheResultAttribute)GetCustomAttribute(method, typeof(CacheResultAttribute));
                CacheResultItemsAttribute[] itemInfoArray = (CacheResultItemsAttribute[])GetCustomAttributes(method, typeof(CacheResultItemsAttribute));

                cacheResultInfo = new CacheResultInfo(resultInfo, itemInfoArray);
                _cacheResultAttributeCache[method] = cacheResultInfo;
            }
            return cacheResultInfo;
        }
        private CacheResultInfo GetCacheResultInfo(MethodInfo method)
        {
            CacheResultInfo cacheResultInfo = (CacheResultInfo)_cacheResultAttributeCache[method];

            // no need for locking here - last one wins
            if (cacheResultInfo == null)
            {
                CacheResultAttribute        resultInfo    = (CacheResultAttribute)GetCustomAttribute(method, typeof(CacheResultAttribute));
                CacheResultItemsAttribute[] itemInfoArray = (CacheResultItemsAttribute[])GetCustomAttributes(method, typeof(CacheResultItemsAttribute));

                cacheResultInfo = new CacheResultInfo(resultInfo, itemInfoArray);
                _cacheResultAttributeCache[method] = cacheResultInfo;
            }
            return(cacheResultInfo);
        }
        /// <summary>
        /// Applies caching around a method invocation.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This method tries to retrieve an object from the cache, using the supplied
        /// <paramref name="invocation"/> to generate a cache key. If an object is found
        /// in the cache, the cached value is returned and the method call does not
        /// proceed any further down the invocation chain.
        /// </p>
        /// <p>
        /// If object does not exist in the cache, the advised method is called (using
        /// <see cref="AopAlliance.Intercept.IJoinpoint.Proceed()"/>)
        /// and any return value is cached for the next method invocation.
        /// </p>
        /// </remarks>
        /// <param name="invocation">
        /// The method invocation that is being intercepted.
        /// </param>
        /// <returns>
        /// A cached object or the result of the
        /// <see cref="AopAlliance.Intercept.IJoinpoint.Proceed()"/> call.
        /// </returns>
        /// <exception cref="System.Exception">
        /// If any of the interceptors in the chain or the target object itself
        /// throws an exception.
        /// </exception>
        public object Invoke(IMethodInvocation invocation)
        {
            CacheResultInfo cacheResultInfo = GetCacheResultInfo(invocation.Method);

            // prepare variables for SpEL expressions
            IDictionary vars = PrepareVariables(invocation.Method, invocation.Arguments);

            bool   cacheHit    = false;
            object returnValue = GetReturnValue(invocation, cacheResultInfo.ResultInfo, vars, out cacheHit);

            if (!cacheHit && cacheResultInfo.ItemInfoArray.Length > 0 && returnValue is IEnumerable)
            {
                CacheResultItems((IEnumerable)returnValue, cacheResultInfo.ItemInfoArray, vars);
            }

            return(returnValue);
        }