/src/LinFu.AOP.Interfaces/BaseMethodReplacementProvider.cs

http://github.com/philiplaureano/LinFu · C# · 81 lines · 35 code · 10 blank · 36 comment · 3 complexity · c4538626875f54cf9ea85bc029ec8fbd MD5 · raw file

  1. namespace LinFu.AOP.Interfaces
  2. {
  3. /// <summary>
  4. /// Represents the boilerplate implementation for a <see cref="IMethodReplacementProvider" /> instance.
  5. /// </summary>
  6. public abstract class BaseMethodReplacementProvider : IMethodReplacementProvider, IAroundInvoke
  7. {
  8. private readonly ICallCounter _counter = new MultiThreadedCallCounter();
  9. /// <summary>
  10. /// The hook method that is called after each intercepted method is called.
  11. /// </summary>
  12. /// <param name="context">The context of the method call that is being intercepted.</param>
  13. /// <param name="returnValue">The value returned from the method call</param>
  14. public void AfterInvoke(IInvocationInfo context, object returnValue)
  15. {
  16. _counter.Decrement(context);
  17. }
  18. /// <summary>
  19. /// The hook method that is called after each intercepted method is called.
  20. /// </summary>
  21. /// <param name="context">The context of the method call that is being intercepted.</param>
  22. public void BeforeInvoke(IInvocationInfo context)
  23. {
  24. _counter.Increment(context);
  25. }
  26. /// <summary>
  27. /// Determines whether or not the current method implementation can be replaced.
  28. /// </summary>
  29. /// <param name="host">The target instance of the method call.</param>
  30. /// <param name="context">The <see cref="IInvocationInfo" /> that describes the context of the method call.</param>
  31. /// <returns><c>true</c> if the method can be intercepted; otherwise, it will return <c>false</c>.</returns>
  32. public bool CanReplace(object host, IInvocationInfo context)
  33. {
  34. var pendingCalls = _counter.GetPendingCalls(context);
  35. if (pendingCalls > 0)
  36. return false;
  37. return ShouldReplace(host, context);
  38. }
  39. /// <summary>
  40. /// Obtains the <see cref="IInterceptor" /> instance that will be used to replace the current method call.
  41. /// </summary>
  42. /// <param name="host">The target instance of the method call.</param>
  43. /// <param name="context">The <see cref="IInvocationInfo" /> that describes the context of the method call.</param>
  44. /// <returns>The interceptor that will intercept the method call itself.</returns>
  45. public IInterceptor GetMethodReplacement(object host, IInvocationInfo context)
  46. {
  47. var pendingCalls = _counter.GetPendingCalls(context);
  48. if (pendingCalls > 0)
  49. return null;
  50. var methodReplacement = GetReplacement(host, context);
  51. return new CountingInterceptor(_counter, methodReplacement);
  52. }
  53. /// <summary>
  54. /// Determines whether or not a given method should be intercepted or replaced.
  55. /// </summary>
  56. /// <param name="host">The actual object or target instance that hosts the method</param>
  57. /// <param name="context">The context that describes the method call</param>
  58. /// <returns></returns>
  59. protected virtual bool ShouldReplace(object host, IInvocationInfo context)
  60. {
  61. return _counter.GetPendingCalls(context) == 0;
  62. }
  63. /// <summary>
  64. /// Obtains the <see cref="IInterceptor" /> instance that will be used to replace the current method call.
  65. /// </summary>
  66. /// <param name="host">The target instance of the method call.</param>
  67. /// <param name="context">The <see cref="IInvocationInfo" /> that describes the context of the method call.</param>
  68. /// <returns>The interceptor that will intercept the method call itself.</returns>
  69. protected abstract IInterceptor GetReplacement(object host, IInvocationInfo context);
  70. }
  71. }