PageRenderTime 43ms CodeModel.GetById 20ms app.highlight 7ms RepoModel.GetById 13ms app.codeStats 0ms

/src/LinFu.Proxy/ProxyMethodBuilder.cs

http://github.com/philiplaureano/LinFu
C# | 135 lines | 69 code | 28 blank | 38 comment | 9 complexity | f970b387c29a2c0f215ecd954f9fcebf MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Reflection;
  5using LinFu.IoC.Configuration;
  6using LinFu.IoC.Interfaces;
  7using LinFu.Proxy.Interfaces;
  8using LinFu.Reflection.Emit;
  9using Mono.Cecil;
 10using MethodAttributes = Mono.Cecil.MethodAttributes;
 11using MethodImplAttributes = Mono.Cecil.MethodImplAttributes;
 12
 13namespace LinFu.Proxy
 14{
 15    /// <summary>
 16    ///     Represents the default implementation of the
 17    ///     <see cref="IMethodBuilder" /> interface.
 18    /// </summary>
 19    [Implements(typeof(IMethodBuilder), LifecycleType.OncePerRequest, ServiceName = "ProxyMethodBuilder")]
 20    public class ProxyMethodBuilder : IMethodBuilder, IInitialize
 21    {
 22        /// <summary>
 23        ///     Initializes the <see cref="ProxyMethodBuilder" /> class with the default property values.
 24        /// </summary>
 25        public ProxyMethodBuilder()
 26        {
 27            Emitter = new MethodBodyEmitter();
 28        }
 29
 30        /// <summary>
 31        ///     The <see cref="IMethodBodyEmitter" /> instance that will be
 32        ///     responsible for generating the method body.
 33        /// </summary>
 34        public virtual IMethodBodyEmitter Emitter { get; set; }
 35
 36
 37        /// <summary>
 38        ///     Initializes the class with the <paramref name="source" /> container.
 39        /// </summary>
 40        /// <param name="source">The <see cref="IServiceContainer" /> instance that will create the class instance.</param>
 41        public virtual void Initialize(IServiceContainer source)
 42        {
 43            Emitter = (IMethodBodyEmitter) source.GetService(typeof(IMethodBodyEmitter));
 44        }
 45
 46
 47        /// <summary>
 48        ///     Creates a method that matches the signature defined in the
 49        ///     <paramref name="method" /> parameter.
 50        /// </summary>
 51        /// <param name="targetType">The type that will host the new method.</param>
 52        /// <param name="method">The method from which the signature will be derived.</param>
 53        public virtual MethodDefinition CreateMethod(TypeDefinition targetType, MethodInfo method)
 54        {
 55            var module = targetType.Module;
 56            var methodName = method.Name;
 57
 58            // If the method is a member defined on an interface type,
 59            // we need to rename the method to avoid
 60            // any naming conflicts in the type itself
 61            if (method.DeclaringType.IsInterface)
 62            {
 63                var parentName = method.DeclaringType.FullName;
 64
 65                // Rename the parent type to its fully qualified name
 66                // if it is a generic type
 67                methodName = string.Format("{0}.{1}", parentName, methodName);
 68            }
 69
 70            var baseAttributes = MethodAttributes.Virtual |
 71                                 MethodAttributes.HideBySig;
 72
 73            var attributes = default(MethodAttributes);
 74
 75
 76            if (method.IsFamilyOrAssembly)
 77                attributes = baseAttributes | MethodAttributes.FamORAssem;
 78
 79            if (method.IsFamilyAndAssembly)
 80                attributes = baseAttributes | MethodAttributes.FamANDAssem;
 81
 82            if (method.IsPublic)
 83                attributes = baseAttributes | MethodAttributes.Public;
 84
 85
 86            // Build the list of parameter types
 87            var parameterTypes = (from param in method.GetParameters()
 88                let type = param.ParameterType
 89                let importedType = type
 90                select importedType).ToArray();
 91
 92
 93            //Build the list of generic parameter types
 94            var genericParameterTypes = method.GetGenericArguments();
 95
 96            var newMethod = targetType.DefineMethod(methodName, attributes,
 97                method.ReturnType, parameterTypes,
 98                genericParameterTypes);
 99
100            newMethod.Body.InitLocals = true;
101            newMethod.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed;
102            newMethod.HasThis = true;
103
104            // Match the generic type arguments
105            var typeArguments = method.GetGenericArguments();
106
107            if (typeArguments != null || typeArguments.Length > 0)
108                MatchGenericArguments(newMethod, typeArguments);
109
110            var originalMethodRef = module.Import(method);
111            newMethod.Overrides.Add(originalMethodRef);
112
113
114            // Define the method body
115            if (Emitter != null)
116                Emitter.Emit(method, newMethod);
117
118            return newMethod;
119        }
120
121
122        /// <summary>
123        ///     Matches the generic parameters of <paramref name="newMethod">a target method</paramref>
124        /// </summary>
125        /// <param name="newMethod">The generic method that contains the generic type arguments.</param>
126        /// <param name="typeArguments">
127        ///     The array of <see cref="Type" /> objects that describe the generic parameters for the
128        ///     current method.
129        /// </param>
130        private static void MatchGenericArguments(MethodDefinition newMethod, ICollection<Type> typeArguments)
131        {
132            foreach (var argument in typeArguments) newMethod.AddGenericParameter(argument);
133        }
134    }
135}