/src/LinFu.IoC/Configuration/BaseMethodBuilder.cs

http://github.com/philiplaureano/LinFu · C# · 101 lines · 45 code · 15 blank · 41 comment · 1 complexity · 2fce02cd61b78a5dea23e1a59de56f86 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Reflection.Emit;
  6. using LinFu.IoC.Configuration.Interfaces;
  7. namespace LinFu.IoC.Configuration
  8. {
  9. /// <summary>
  10. /// Represents the default implementation of the <see cref="IMethodBuilder{TMethod}" /> interface.
  11. /// </summary>
  12. /// <typeparam name="TMethod">The method type to generate.</typeparam>
  13. public abstract class BaseMethodBuilder<TMethod> : IMethodBuilder<TMethod>
  14. where TMethod : MethodBase
  15. {
  16. /// <summary>
  17. /// Creates a method from the <paramref name="existingMethod" />.
  18. /// </summary>
  19. /// <param name="existingMethod">The method that will be used to define the new method.</param>
  20. /// <returns>A method based on the old method.</returns>
  21. public MethodBase CreateMethod(TMethod existingMethod)
  22. {
  23. var returnType = GetReturnType(existingMethod);
  24. var parameterTypes = (from p in existingMethod.GetParameters()
  25. select p.ParameterType).ToArray();
  26. // Determine the method signature
  27. var parameterList = GetParameterList(existingMethod, parameterTypes);
  28. var declaringType = existingMethod.DeclaringType;
  29. var module = declaringType.Module;
  30. var dynamicMethod = new DynamicMethod(string.Empty, returnType, parameterList.ToArray(), module);
  31. var IL = dynamicMethod.GetILGenerator();
  32. // Push the target instance, if necessary
  33. PushInstance(IL, existingMethod);
  34. // Push the method arguments
  35. PushMethodArguments(IL, existingMethod);
  36. // Call the target method
  37. EmitCall(IL, existingMethod);
  38. // Unbox the return type
  39. IL.Emit(OpCodes.Ret);
  40. return dynamicMethod;
  41. }
  42. /// <summary>
  43. /// Pushes the method arguments onto the stack.
  44. /// </summary>
  45. /// <param name="IL">The <see cref="ILGenerator" /> of the target method body.</param>
  46. /// <param name="targetMethod">The target method that will be invoked.</param>
  47. protected virtual void PushMethodArguments(ILGenerator IL, MethodBase targetMethod)
  48. {
  49. var parameterTypes = (from p in targetMethod.GetParameters()
  50. select p.ParameterType).ToArray();
  51. // Push the method arguments onto the stack
  52. var parameterCount = parameterTypes.Length;
  53. for (var index = 0; index < parameterCount; index++) IL.Emit(OpCodes.Ldarg, index);
  54. }
  55. /// <summary>
  56. /// Determines the parameter types of the dynamically generated method.
  57. /// </summary>
  58. /// <param name="existingMethod">The target method.</param>
  59. /// <param name="parameterTypes">The target method argument types.</param>
  60. /// <returns>The list of <see cref="System.Type" /> objects that describe the signature of the method to generate.</returns>
  61. protected virtual IList<Type> GetParameterList(TMethod existingMethod, Type[] parameterTypes)
  62. {
  63. return new List<Type>(parameterTypes);
  64. }
  65. /// <summary>
  66. /// Pushes the method target onto the stack.
  67. /// </summary>
  68. /// <param name="IL">The <see cref="ILGenerator" /> that belongs to the method body.</param>
  69. /// <param name="method">The current method.</param>
  70. protected virtual void PushInstance(ILGenerator IL, TMethod method)
  71. {
  72. }
  73. /// <summary>
  74. /// Determines the return type from the target <paramref name="method" />.
  75. /// </summary>
  76. /// <param name="method">The target method itself.</param>
  77. /// <returns>The method return type.</returns>
  78. protected abstract Type GetReturnType(TMethod method);
  79. /// <summary>
  80. /// Emits the instruction to call the target <paramref name="method" />
  81. /// </summary>
  82. /// <param name="IL">The <see cref="ILGenerator" /> of the target method body.</param>
  83. /// <param name="method">The method that will be invoked.</param>
  84. protected abstract void EmitCall(ILGenerator IL, TMethod method);
  85. }
  86. }