/src/LinFu.IoC/Configuration/Injectors/AutoMemberInjector.cs

http://github.com/philiplaureano/LinFu · C# · 142 lines · 72 code · 22 blank · 48 comment · 17 complexity · 9373dd91c228b629ce9b77b935c01e59 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using LinFu.IoC.Configuration.Interfaces;
  6. using LinFu.IoC.Interfaces;
  7. using LinFu.Proxy.Interfaces;
  8. namespace LinFu.IoC.Configuration
  9. {
  10. /// <summary>
  11. /// The base class that defines the behavior for automatically injecting service
  12. /// instances into type member instances.
  13. /// </summary>
  14. /// <typeparam name="TMember"></typeparam>
  15. public abstract class AutoMemberInjector<TMember> : IPostProcessor, IContainerPlugin
  16. where TMember : MemberInfo
  17. {
  18. private static readonly HashSet<Type> _excludedServices =
  19. new HashSet<Type>(new[]
  20. {
  21. typeof(IMemberInjectionFilter<TMember>), typeof(IArgumentResolver),
  22. typeof(IPropertySetter)
  23. });
  24. private bool _inProcess;
  25. /// <summary>
  26. /// Does absolutely nothing.
  27. /// </summary>
  28. /// <param name="target">The target container.</param>
  29. public void BeginLoad(IServiceContainer target)
  30. {
  31. }
  32. /// <summary>
  33. /// Inserts the <see cref="AutoPropertyInjector" /> class at the end
  34. /// of the PostProcessor chain.
  35. /// </summary>
  36. /// <param name="target">The target container.</param>
  37. public void EndLoad(IServiceContainer target)
  38. {
  39. target.PostProcessors.Add(this);
  40. }
  41. /// <summary>
  42. /// Automatically injects service instances
  43. /// into properties as soon as they are initialized.
  44. /// </summary>
  45. /// <param name="result">
  46. /// The service request result that contains the service whose members will be injected with service
  47. /// instances.
  48. /// </param>
  49. public void PostProcess(IServiceRequestResult result)
  50. {
  51. // Prevent recursion
  52. if (_inProcess)
  53. return;
  54. lock (this)
  55. {
  56. _inProcess = true;
  57. }
  58. AutoInject(result);
  59. lock (this)
  60. {
  61. _inProcess = false;
  62. }
  63. }
  64. /// <summary>
  65. /// Injects services from the <paramref name="container" /> into the target <paramref name="member" /> instance.
  66. /// </summary>
  67. /// <param name="target">The target object.</param>
  68. /// <param name="member">The <typeparamref name="TMember" /> instance that will store the service instance.</param>
  69. /// <param name="argumentResolver">
  70. /// The <see cref="IArgumentResolver" /> that will determine which arguments will be
  71. /// assigned to the target member.
  72. /// </param>
  73. /// <param name="additionalArguments">
  74. /// The additional arguments that were passed to the <see cref="IServiceRequestResult" />
  75. /// during the instantiation process.
  76. /// </param>
  77. /// <param name="container">The container that will provide the service instances.</param>
  78. protected abstract void Inject(object target, TMember member, IArgumentResolver argumentResolver,
  79. IServiceContainer container, object[] additionalArguments);
  80. /// <summary>
  81. /// Injects a member service dependency into a target service instance.
  82. /// </summary>
  83. /// <param name="result">The <see cref="IServiceRequestResult" /> that will be processed for injection.</param>
  84. private void AutoInject(IServiceRequestResult result)
  85. {
  86. // Ignore the excluded services
  87. if (_excludedServices.Contains(result.ServiceType))
  88. return;
  89. if (result.ServiceType.IsGenericType)
  90. {
  91. var baseDefinition = result.ServiceType.GetGenericTypeDefinition();
  92. if (baseDefinition == typeof(IMemberInjectionFilter<>))
  93. return;
  94. }
  95. var container = result.Container;
  96. if (!container.Contains(typeof(IMemberInjectionFilter<TMember>)))
  97. return;
  98. var filter = container.GetService<IMemberInjectionFilter<TMember>>();
  99. if (filter == null || result.ActualResult == null)
  100. return;
  101. // Determine which members can be injected
  102. var targetType = result.ActualResult.GetType();
  103. // Use the base class if the
  104. // target type is a proxy type
  105. if (typeof(IProxy).IsAssignableFrom(targetType) && targetType.BaseType != typeof(object))
  106. targetType = targetType.BaseType;
  107. var members = filter.GetInjectableMembers(targetType).ToList();
  108. if (members.Count == 0)
  109. return;
  110. // Use the resolver to determine
  111. // which value should be injected
  112. // into the member
  113. var resolver = container.GetService<IArgumentResolver>();
  114. if (resolver == null)
  115. return;
  116. var target = result.ActualResult;
  117. foreach (var member in members) Inject(target, member, resolver, container, result.AdditionalArguments);
  118. }
  119. }
  120. }