/src/LinFu.IoC/Configuration/BaseMethodInvoke.cs

http://github.com/philiplaureano/LinFu · C# · 113 lines · 56 code · 17 blank · 40 comment · 3 complexity · db966b4fd31c7ae69c377d6ade78f79e MD5 · raw file

  1. using System.Collections.Generic;
  2. using System.Reflection;
  3. using System.Reflection.Emit;
  4. using LinFu.IoC.Configuration.Interfaces;
  5. using LinFu.IoC.Interfaces;
  6. using LinFu.Reflection;
  7. namespace LinFu.IoC.Configuration
  8. {
  9. /// <summary>
  10. /// Represents the default implementation of the <see cref="IMethodInvoke{TMethod}" /> interface.
  11. /// </summary>
  12. public abstract class BaseMethodInvoke<TMethod> : IMethodInvoke<TMethod>, IInitialize
  13. where TMethod : MethodBase
  14. {
  15. private static readonly Dictionary<TMethod, MethodBase> _cache = new Dictionary<TMethod, MethodBase>();
  16. /// <summary>
  17. /// Initializes the class with the default values.
  18. /// </summary>
  19. public BaseMethodInvoke()
  20. {
  21. // HACK: Set the ReflectionMethodBuilder as the default builder
  22. if (typeof(TMethod) == typeof(MethodInfo))
  23. MethodBuilder = new ReflectionMethodBuilder<MethodInfo>() as IMethodBuilder<TMethod>;
  24. }
  25. /// <summary>
  26. /// Gets or sets the value indicating the method builder that will be used to
  27. /// create the target method.
  28. /// </summary>
  29. protected IMethodBuilder<TMethod> MethodBuilder { get; set; }
  30. /// <summary>
  31. /// Initializes the class with the <paramref name="source">source service container.</paramref>
  32. /// </summary>
  33. /// <param name="source">The <see cref="IServiceContainer" /> instance that will initialize this class.</param>
  34. public void Initialize(IServiceContainer source)
  35. {
  36. MethodBuilder = source.GetService<IMethodBuilder<TMethod>>();
  37. }
  38. /// <summary>
  39. /// Instantiates an object instance with the <paramref name="targetMethod" />
  40. /// and <paramref name="arguments" />.
  41. /// </summary>
  42. /// <param name="target">The target object reference. In this particular case, this parameter will be ignored.</param>
  43. /// <param name="targetMethod">The target method.</param>
  44. /// <param name="arguments">The arguments to be used with the method.</param>
  45. /// <returns>An object reference that represents the method return value.</returns>
  46. public object Invoke(object target, TMethod targetMethod,
  47. object[] arguments)
  48. {
  49. object result = null;
  50. // Reuse the cached results, if possible
  51. if (!_cache.ContainsKey(targetMethod))
  52. GenerateTargetMethod(targetMethod);
  53. var factoryMethod = _cache[targetMethod];
  54. try
  55. {
  56. result = DoInvoke(target, targetMethod, factoryMethod, arguments);
  57. }
  58. catch (TargetInvocationException ex)
  59. {
  60. throw ex.InnerException;
  61. }
  62. return result;
  63. }
  64. /// <summary>
  65. /// Invokes the <paramref name="targetMethod" /> with the given <paramref name="arguments" />.
  66. /// </summary>
  67. /// <param name="target">The target instance.</param>
  68. /// <param name="originalMethod">The original method that describes the target method.</param>
  69. /// <param name="targetMethod">The actual method that will be invoked.</param>
  70. /// <param name="arguments">The method arguments.</param>
  71. /// <returns>The return value from the target method.</returns>
  72. protected virtual object DoInvoke(object target, TMethod originalMethod, MethodBase targetMethod,
  73. object[] arguments)
  74. {
  75. var result = targetMethod.Invoke(target, arguments);
  76. return result;
  77. }
  78. /// <summary>
  79. /// Creates a <see cref="DynamicMethod" /> that will be used as the
  80. /// factory method and stores it in the method cache.
  81. /// </summary>
  82. /// <param name="targetMethod">The constructor that will be used to instantiate the target type.</param>
  83. protected virtual void GenerateTargetMethod(TMethod targetMethod)
  84. {
  85. MethodBase result = null;
  86. // HACK: Since the Mono runtime does not yet implement the DynamicMethod class,
  87. // we'll actually have to use the constructor itself to construct the target type
  88. result = Runtime.IsRunningOnMono ? targetMethod : MethodBuilder.CreateMethod(targetMethod);
  89. // Save the results
  90. lock (_cache)
  91. {
  92. _cache[targetMethod] = result;
  93. }
  94. }
  95. }
  96. }