/src/LinFu.AOP/Emitters/EmitBeforeInvoke.cs

http://github.com/philiplaureano/LinFu · C# · 99 lines · 54 code · 16 blank · 29 comment · 1 complexity · d23f339052353794dfa96e991ac3305f MD5 · raw file

  1. using System;
  2. using LinFu.AOP.Cecil.Interfaces;
  3. using LinFu.AOP.Interfaces;
  4. using LinFu.Reflection.Emit;
  5. using Mono.Cecil.Cil;
  6. namespace LinFu.AOP.Cecil
  7. {
  8. /// <summary>
  9. /// Represents a type that emits the call to the <see cref="IBeforeInvoke" /> instance.
  10. /// </summary>
  11. public class EmitBeforeInvoke : IInstructionEmitter
  12. {
  13. private readonly VariableDefinition _invocationInfo;
  14. private readonly Type _registryType;
  15. private readonly VariableDefinition _surroundingClassImplementation;
  16. private readonly VariableDefinition _surroundingImplementation;
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="EmitBeforeInvoke" /> class.
  19. /// </summary>
  20. /// <param name="invocationInfo">The variable that contains the <see cref="IInvocationInfo" /> instance.</param>
  21. /// <param name="surroundingClassImplementation">
  22. /// The variable that contains the class-level <see cref="IAroundInvoke" />
  23. /// instance.
  24. /// </param>
  25. /// <param name="surroundingImplementation">
  26. /// The variable that contains the instance-level <see cref="IAroundInvoke" />
  27. /// instance.
  28. /// </param>
  29. /// <param name="registryType">
  30. /// The interception registry type that will be responsible for handling class-level
  31. /// interception events.
  32. /// </param>
  33. public EmitBeforeInvoke(VariableDefinition invocationInfo,
  34. VariableDefinition surroundingClassImplementation,
  35. VariableDefinition surroundingImplementation,
  36. Type registryType)
  37. {
  38. _invocationInfo = invocationInfo;
  39. _surroundingClassImplementation = surroundingClassImplementation;
  40. _surroundingImplementation = surroundingImplementation;
  41. _registryType = registryType;
  42. }
  43. /// <summary>
  44. /// Emits the call to the <see cref="IAfterInvoke" /> instance.
  45. /// </summary>
  46. /// <param name="IL">The <see cref="ILProcessor" /> that points to the current method body.</param>
  47. public void Emit(ILProcessor IL)
  48. {
  49. var targetMethod = IL.Body.Method;
  50. var declaringType = targetMethod.DeclaringType;
  51. var module = declaringType.Module;
  52. var getSurroundingClassImplementation = new GetSurroundingClassImplementation(_invocationInfo,
  53. _surroundingClassImplementation,
  54. _registryType.GetMethod(
  55. "GetSurroundingImplementation"));
  56. // var classAroundInvoke = AroundInvokeRegistry.GetSurroundingImplementation(info);
  57. getSurroundingClassImplementation.Emit(IL);
  58. // classAroundInvoke.BeforeInvoke(info);
  59. var skipInvoke = IL.Create(OpCodes.Nop);
  60. IL.Emit(OpCodes.Ldloc, _surroundingClassImplementation);
  61. IL.Emit(OpCodes.Brfalse, skipInvoke);
  62. var beforeInvoke = module.ImportMethod<IBeforeInvoke>("BeforeInvoke");
  63. // surroundingImplementation.BeforeInvoke(invocationInfo);
  64. IL.Emit(OpCodes.Ldloc, _surroundingClassImplementation);
  65. IL.Emit(OpCodes.Ldloc, _invocationInfo);
  66. IL.Emit(OpCodes.Callvirt, beforeInvoke);
  67. IL.Append(skipInvoke);
  68. // if (surroundingImplementation != null) {
  69. if (!targetMethod.HasThis)
  70. return;
  71. var skipInvoke1 = IL.Create(OpCodes.Nop);
  72. IL.Emit(OpCodes.Ldloc, _surroundingImplementation);
  73. IL.Emit(OpCodes.Brfalse, skipInvoke1);
  74. var beforeInvoke1 = module.ImportMethod<IBeforeInvoke>("BeforeInvoke");
  75. // surroundingImplementation.BeforeInvoke(invocationInfo);
  76. IL.Emit(OpCodes.Ldloc, _surroundingImplementation);
  77. IL.Emit(OpCodes.Ldloc, _invocationInfo);
  78. IL.Emit(OpCodes.Callvirt, beforeInvoke1);
  79. IL.Append(skipInvoke1);
  80. // }
  81. }
  82. }
  83. }