PageRenderTime 39ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/LinFu.AOP/MethodBodyInterception/InterceptMethodBody.cs

http://github.com/philiplaureano/LinFu
C# | 145 lines | 95 code | 19 blank | 31 comment | 1 complexity | 0c85bc297c57f20a353a4acfc859dded MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using LinFu.AOP.Cecil.Interfaces;
  5. using LinFu.AOP.Interfaces;
  6. using LinFu.Reflection.Emit;
  7. using Mono.Cecil;
  8. using Mono.Cecil.Cil;
  9. namespace LinFu.AOP.Cecil
  10. {
  11. /// <summary>
  12. /// Represents a method rewriter type that adds interception capabilities to any given method body.
  13. /// </summary>
  14. public class InterceptMethodBody : BaseMethodRewriter, IMethodWeaver
  15. {
  16. private readonly Func<MethodReference, bool> _methodFilter;
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="InterceptMethodBody" /> class.
  19. /// </summary>
  20. /// <param name="methodFilter">
  21. /// The method filter that will determine the methods with the method bodies that will be
  22. /// intercepted.
  23. /// </param>
  24. public InterceptMethodBody(Func<MethodReference, bool> methodFilter)
  25. {
  26. _methodFilter = methodFilter;
  27. }
  28. /// <summary>
  29. /// Determines whether or not the given method should be modified.
  30. /// </summary>
  31. /// <param name="targetMethod">The target method.</param>
  32. /// <returns>A <see cref="bool" /> indicating whether or not a method should be rewritten.</returns>
  33. protected override bool ShouldRewrite(MethodDefinition targetMethod)
  34. {
  35. return _methodFilter(targetMethod);
  36. }
  37. /// <summary>
  38. /// Rewrites the instructions in the target method body.
  39. /// </summary>
  40. /// <param name="method">The target method.</param>
  41. /// <param name="IL">The <see cref="ILProcessor" /> instance that represents the method body.</param>
  42. /// <param name="oldInstructions">The IL instructions of the original method body.</param>
  43. protected override void RewriteMethodBody(MethodDefinition method, ILProcessor IL,
  44. IEnumerable<Instruction> oldInstructions)
  45. {
  46. if (IsExcluded(method))
  47. {
  48. AddOriginalInstructions(IL, oldInstructions);
  49. return;
  50. }
  51. var interceptionDisabled = method.AddLocal<bool>();
  52. var invocationInfo = method.AddLocal<IInvocationInfo>();
  53. var aroundInvokeProvider = method.AddLocal<IAroundInvokeProvider>();
  54. var methodReplacementProvider = method.AddLocal<IMethodReplacementProvider>();
  55. var returnValue = method.AddLocal<object>();
  56. var classMethodReplacementProvider = method.AddLocal<IMethodReplacementProvider>();
  57. Func<ModuleDefinition, MethodReference> getInstanceMethodReplacementProviderMethod =
  58. module => module.Import(typeof(IMethodReplacementHost).GetMethod("get_MethodBodyReplacementProvider"));
  59. var parameters = new MethodBodyRewriterParameters(IL,
  60. oldInstructions,
  61. interceptionDisabled,
  62. invocationInfo, returnValue,
  63. methodReplacementProvider,
  64. aroundInvokeProvider,
  65. classMethodReplacementProvider,
  66. getInstanceMethodReplacementProviderMethod,
  67. typeof(AroundMethodBodyRegistry));
  68. var emitter = new InvocationInfoEmitter(true);
  69. IInstructionEmitter getMethodReplacementProvider =
  70. new GetMethodReplacementProvider(methodReplacementProvider, method,
  71. getInstanceMethodReplacementProviderMethod);
  72. IInstructionEmitter getInterceptionDisabled = new GetInterceptionDisabled(parameters);
  73. ISurroundMethodBody surroundMethodBody = new SurroundMethodBody(parameters, "AroundMethodBodyProvider");
  74. IInstructionEmitter getClassMethodReplacementProvider = new GetClassMethodReplacementProvider(parameters,
  75. module =>
  76. module.Import(
  77. typeof(
  78. MethodBodyReplacementProviderRegistry
  79. ).GetMethod
  80. ("GetProvider")));
  81. IInstructionEmitter addMethodReplacement = new AddMethodReplacementImplementation(parameters);
  82. var rewriter = new InterceptAndSurroundMethodBody(emitter, getInterceptionDisabled, surroundMethodBody,
  83. getMethodReplacementProvider,
  84. getClassMethodReplacementProvider, addMethodReplacement,
  85. parameters);
  86. // Determine whether or not the method should be intercepted
  87. rewriter.Rewrite(method, IL, oldInstructions);
  88. }
  89. private void AddOriginalInstructions(ILProcessor IL, IEnumerable<Instruction> oldInstructions)
  90. {
  91. foreach (var instruction in oldInstructions) IL.Append(instruction);
  92. }
  93. private bool IsExcluded(MethodDefinition method)
  94. {
  95. var excludedTypes = new[]
  96. {
  97. typeof(IMethodReplacementHost),
  98. typeof(IModifiableType), typeof(IActivatorHost),
  99. typeof(IFieldInterceptionHost), typeof(IAroundInvokeHost)
  100. };
  101. var excludedMethods = (from type in excludedTypes
  102. from currentMethod in type.GetMethods()
  103. select currentMethod.Name).ToList();
  104. var methodName = method.Name;
  105. return excludedMethods.Contains(methodName);
  106. }
  107. /// <summary>
  108. /// Determines whether or not the current item should be modified.
  109. /// </summary>
  110. /// <param name="item">The target item.</param>
  111. /// <returns>Returns <c>true</c> if the current item can be modified; otherwise, it should return <c>false.</c></returns>
  112. public bool ShouldWeave(MethodDefinition item)
  113. {
  114. return ShouldRewrite(item);
  115. }
  116. /// <summary>
  117. /// Modifies the target <paramref name="item" />.
  118. /// </summary>
  119. /// <param name="item">The item to be modified.</param>
  120. public void Weave(MethodDefinition item)
  121. {
  122. var oldInstructions = item.Body.Instructions.ToArray();
  123. Rewrite(item, item.GetILGenerator(), oldInstructions);
  124. }
  125. }
  126. }