Exemplo n.º 1
0
        /// <summary>
        /// Defines the IL that caches the result of calling the base method.
        /// </summary>
        /// <param name="il">The il generator to use.</param>
        /// <param name="returnValueLocal">The local that the result of reading from the cache will be stored into.</param>
        /// <param name="cacheKeyLocal">The local variable that contains a reference to the calculated cache key.</param>
        /// <param name="cacheServiceField">The field that contains a reference to the cache service.</param>
        /// <param name="cacheParams">The cacheable method attribute data that describes the cache behavior for the method.</param>
        private static void CacheResult(ILGenerator il, LocalBuilder returnValueLocal, LocalBuilder cacheKeyLocal, FieldBuilder cacheServiceField, CacheableMethodAttribute cacheParams)
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, cacheServiceField);
            il.Emit(OpCodes.Ldloc, cacheKeyLocal);
            il.Emit(OpCodes.Ldloc, returnValueLocal);
            il.Emit(OpCodes.Ldc_I4, cacheParams.CacheSeconds);

            var methodInfo = typeof(IDynaCacheService)
                             .GetMethod("SetCachedObject")
                             .MakeGenericMethod(returnValueLocal.LocalType);

            il.EmitCall(OpCodes.Callvirt, methodInfo, null);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Defines a method in the dynamic type that wraps the caching behavior around the underlying type's method call.
        /// </summary>
        /// <param name="cacheableModule">The cacheable module.</param>
        /// <param name="cacheServiceField">The cache service field.</param>
        /// <param name="methodInfo">The method info.</param>
        /// <param name="cacheParams">The cacheable method attribute data that describes the cache behavior for the method.</param>
        private static void DefineMethod(TypeBuilder cacheableModule, FieldBuilder cacheServiceField, MethodInfo methodInfo, CacheableMethodAttribute cacheParams)
        {
            if (methodInfo.IsFinal || !methodInfo.IsVirtual)
            {
                throw new DynaCacheException(
                          string.Format("Cacheable methods must be overridable. Correct method <{0}> in type <{1}>.", methodInfo.Name, methodInfo.DeclaringType.Name)
                          );
            }

            var methodParams = methodInfo.GetParameters().ToArray();

            if (methodParams.Any(p => p.ParameterType.IsByRef))
            {
                throw new DynaCacheException(
                          string.Format("Reference parameters (out/ref) are not supported for cacheable methods. Correct method <{0}> in type <{1}>.", methodInfo.Name, methodInfo.DeclaringType.Name)
                          );
            }

            foreach (var methodParam in methodParams)
            {
                var paramType = methodParam.ParameterType;

                if (!(paramType.IsEnum || paramType.ContainsGenericParameters || ToStringableTypes.Contains(paramType) || (paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable <>) && ToStringableTypes.Contains(paramType.GetGenericArguments()[0]))))
                {
                    if (paramType.GetCustomAttributes(typeof(ToStringableAttribute), false).Any())
                    {
                        ToStringableTypes.Add(paramType);
                    }
                    else if (!CustomConverters.ContainsKey(paramType))
                    {
                        throw new DynaCacheException(
                                  String.Format(
                                      "Cacheable method has parameter without unique ToString() implementation: consider writing it and mark parameter type with ToStringable attribute." +
                                      "Method: {0}, Parameter {1} of type {2}",
                                      methodInfo.Name, methodParam.Name, paramType));
                    }
                }
            }

            var method = cacheableModule.DefineMethod(
                methodInfo.Name,
                MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot,
                methodInfo.ReturnType,
                methodParams.Select(pa => pa.ParameterType).ToArray());

            var il                 = method.GetILGenerator();
            var cacheKeyLocal      = il.DeclareLocal(typeof(string));
            var returnValueLocal   = il.DeclareLocal(method.ReturnType);
            var cacheOutValueLocal = il.DeclareLocal(typeof(object));

            var cacheKeyTemplate = CreateCacheKeyTemplate(methodInfo, methodParams);

            FormatCacheKey(methodParams, il, cacheKeyLocal, cacheKeyTemplate);
            TryGetFromCache(cacheOutValueLocal, cacheKeyLocal, returnValueLocal, il, cacheServiceField);
            CallBaseMethod(methodInfo, methodParams, il, returnValueLocal);
            CacheResult(il, returnValueLocal, cacheKeyLocal, cacheServiceField, cacheParams);

            il.Emit(OpCodes.Ldloc, returnValueLocal);
            il.Emit(OpCodes.Ret);
        }