PageRenderTime 35ms CodeModel.GetById 28ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

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