/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

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