Esempio n. 1
0
        public static bool TryInject(
            IServiceRegistrationProvider serviceProvider,
            object target,
            Type attributeType,
            ITrace logger = null,
            Func <Type, object> instanceProvider = null,
            bool tryConstructArguments           = false,
            bool?requireConstructorAttributes    = null,
            IReadOnlyCollection <Type> constructorAttributeTypes = null)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException(nameof(serviceProvider));
            }
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (attributeType == null)
            {
                throw new ArgumentNullException(nameof(attributeType));
            }
            if ((constructorAttributeTypes == null) ||
                (constructorAttributeTypes.Count == 0))
            {
                constructorAttributeTypes = new[] { typeof(ServiceProviderConstructorAttribute) }
            }
            ;
            ServiceConstructorRequest request
                = new ServiceConstructorRequest(logger ?? TraceSources.For(typeof(ServiceConstructorMethods)));

            request.Logger.Verbose(
                "Injecting '{0}' on '{1}'.",
                attributeType.GetFriendlyFullName(),
                target.GetType().GetFriendlyFullName());
            if (ServiceConstructorMethods.invokeMember(
                    ServiceConstructorMethods.findMethods(target, attributeType, request.TraceStack),
                    true,
                    target,
                    out _,
                    request,
                    serviceProvider,
                    instanceProvider,
                    tryConstructArguments,
                    requireConstructorAttributes,
                    constructorAttributeTypes,
                    false))
            {
                request.Logger.Verbose(
                    "Inject result for '{0}' on '{1}' is true.",
                    attributeType.GetFriendlyFullName(),
                    target.GetType().GetFriendlyFullName());
                return(true);
            }
            request.Logger.Info(
                "Inject result for '{0}' on '{1}' is false.",
                attributeType.GetFriendlyFullName(),
                target.GetType().GetFriendlyFullName());
            return(false);
        }
Esempio n. 2
0
 /// <summary>
 /// The implementation method that constructs and/or returns the
 /// implementation instance.
 /// </summary>
 /// <param name="serviceConstructorRequest">This argument is required here.</param>
 /// <returns>Should be null only if the service is not constructed successfully:
 /// note that this may result in a resolver or constructor error.</returns>
 /// <exception cref="ArgumentNullException"></exception>
 internal object Get(ServiceConstructorRequest serviceConstructorRequest)
 {
     if (serviceConstructorRequest == null)
     {
         throw new ArgumentNullException(nameof(serviceConstructorRequest));
     }
     lock (syncLock) {
         checkIsDisposedUnsafe();
         if (!IsSingleton)
         {
             ConstructedAt = DateTime.UtcNow;
             object instance = InvokeFactory(serviceConstructorRequest);
             if (dependencies != null)
             {
                 dependencies.TryAddRange(serviceConstructorRequest.Dependencies);
             }
             else
             {
                 dependencies
                     = new MultiDictionary <Type, Type>(
                           serviceConstructorRequest.Dependencies,
                           serviceConstructorRequest.Dependencies.Comparer);
             }
             return(instance);
         }
         if (IsSingletonSet)
         {
             return(singleton);
         }
         ConstructedAt  = DateTime.UtcNow;
         singleton      = InvokeFactory(serviceConstructorRequest);
         IsSingletonSet = true;
         dependencies
             = new MultiDictionary <Type, Type>(
                   serviceConstructorRequest.Dependencies,
                   serviceConstructorRequest.Dependencies.Comparer);
         return(singleton);
     }
     object InvokeFactory(ServiceConstructorRequest request)
     => factory != null
                                         ? factory(serviceProvider)
                                         : ServiceConstructorMethods.TryConstruct(
         ImplementationType,
         out object result,
         request,
         serviceProvider,
         null,
         false,
         RequireConstructorAttributes,
         ConstructorAttributeTypes)
                                                         ? result
                                                         : null;
 }
Esempio n. 3
0
        private static Comparison <T> attributeParameterCountSort <T>(IReadOnlyCollection <Type> attributeTypes)
            where T : MethodBase
        {
            int Sort(T x, T y)
            => ServiceConstructorMethods.hasAttributePredicate <T>(attributeTypes)(x)
                                                ? ServiceConstructorMethods.hasAttributePredicate <T>(attributeTypes)(y)
                                                                ? -x.GetParameters().Length.CompareTo(y.GetParameters().Length)
                                                                : -1
                                                : ServiceConstructorMethods.hasAttributePredicate <T>(attributeTypes)(y)
                                                                ? 1
                                                                : -x.GetParameters().Length.CompareTo(y.GetParameters().Length);

            return(Sort);
        }
Esempio n. 4
0
        /// <summary>
        /// Utility method returns all Public and NonPublic constructors,
        /// sorted with the most parameters first.
        /// </summary>
        private static IEnumerable <ConstructorInfo> findConstructors(
            Type type,
            bool?requireAttributes,
            IReadOnlyCollection <Type> attributeTypes,
            ISequence <object> traceStack)
        {
            List <ConstructorInfo> constructors
                = type.GetConstructors(
                      BindingFlags.Instance
                      | BindingFlags.Public
                      | BindingFlags.NonPublic)
                  .ToList();

            if (constructors.Count == 0)
            {
                traceStack.Add($"No constructors found for '{type.GetFriendlyFullName()}'.");
            }
            if (requireAttributes == false)
            {
                constructors.Sort(ServiceConstructorMethods.attributeParameterCountSort <ConstructorInfo>(attributeTypes));
                return(constructors);
            }
            if ((requireAttributes == true) ||
                (constructors.FindIndex(
                     ServiceConstructorMethods.hasAttributePredicate <ConstructorInfo>(attributeTypes))
                 >= 0))
            {
                constructors.RemoveAll(ServiceConstructorMethods.hasAttributePredicate <ConstructorInfo>(attributeTypes, true));
            }
            if (constructors.Count == 0)
            {
                traceStack.Add(
                    $"No selected constructors found for '{type.GetFriendlyFullName()}'"
                    + $" --- {attributeTypes.ToStringCollection(256, t => t.GetFriendlyFullName())}.");
            }
            constructors.Sort(
                ServiceConstructorMethods
                .attributeParameterCountSort <ConstructorInfo>(attributeTypes));
            return(constructors);
        }
Esempio n. 5
0
 public static bool TryConstruct(
     Type targetType,
     out object service,
     ServiceConstructorRequest request,
     IServiceRegistrationProvider serviceProvider,
     Func <Type, object> instanceProvider = null,
     bool tryConstructArguments           = false,
     bool?requireConstructorAttributes    = null,
     IReadOnlyCollection <Type> constructorAttributeTypes = null)
 {
     if (targetType == null)
     {
         throw new ArgumentNullException(nameof(targetType));
     }
     if (request == null)
     {
         throw new ArgumentNullException(nameof(request));
     }
     if (serviceProvider == null)
     {
         throw new ArgumentNullException(nameof(serviceProvider));
     }
     if ((constructorAttributeTypes == null) ||
         (constructorAttributeTypes.Count == 0))
     {
         constructorAttributeTypes = new[] { typeof(ServiceProviderConstructorAttribute) }
     }
     ;
     if (request.ConstructingTypes.Contains(targetType))
     {
         request.TraceStack.Add(
             "Found a recursive constructor dependency"
             + $": '{targetType.GetFriendlyFullName()}'"
             + " ... cannot continue.");
         service = null;
         return(false);
     }
     request.ConstructingTypes.Add(targetType);
     request.Logger.Verbose("Constructing {0}.", targetType.GetFriendlyFullName());
     if (ServiceConstructorMethods.invokeMember(
             ServiceConstructorMethods.findConstructors(
                 targetType,
                 requireConstructorAttributes,
                 constructorAttributeTypes,
                 request.TraceStack),
             false,
             null,
             out service,
             request,
             serviceProvider,
             instanceProvider,
             tryConstructArguments,
             requireConstructorAttributes,
             constructorAttributeTypes,
             false))
     {
         request.Logger.Verbose(
             "Construct result for '{0}' is true: '{1}'.",
             targetType.GetFriendlyFullName(),
             service.GetType().GetFriendlyFullName());
         request.ConstructingTypes.Remove(targetType);
         return(true);
     }
     request.Logger.Warning("Construct result for '{0}' is false.", targetType.GetFriendlyFullName());
     request.ConstructingTypes.Remove(targetType);
     return(false);
 }
Esempio n. 6
0
        private static bool invokeMember(
            IEnumerable <MethodBase> members,
            bool isMethod,
            object methodTarget,
            out object newInstance,
            ServiceConstructorRequest request,
            IServiceRegistrationProvider serviceProvider,
            Func <Type, object> instanceProvider,
            bool tryConstructArguments,
            bool?requireConstructorAttributes,
            IReadOnlyCollection <Type> constructorAttributeTypes,
            bool isRecursed)
        {
            newInstance = null;
            bool success = false;

            foreach (MethodBase methodBase in members)
            {
                ParameterInfo[] parameters = methodBase.GetParameters();
                if (parameters.Length == 0)
                {
                    success = isMethod
                                                        ? ServiceConstructorMethods.tryInvokeMethod(
                        methodTarget,
                        (MethodInfo)methodBase,
                        new object[0],
                        request.TraceStack)
                                                        : ServiceConstructorMethods.tryInvokeConstructor(
                        (ConstructorInfo)methodBase,
                        new object[0],
                        out newInstance,
                        request.TraceStack);
                    break;
                }
                List <object> arguments = new List <object>(parameters.Length);
                foreach (ParameterInfo parameterInfo in parameters)
                {
                    if (ServiceConstructorMethods.tryResolve(
                            parameterInfo.ParameterType,
                            out object parameterResult,
                            request,
                            serviceProvider,
                            instanceProvider,
                            !tryConstructArguments))
                    {
                        arguments.Add(parameterResult);
                        continue;
                    }
                    if (tryConstructArguments)
                    {
                        if (request.ConstructingTypes.Contains(parameterInfo.ParameterType))
                        {
                            request.TraceStack.Add(
                                "Found a recursive constructor dependency"
                                + $": '{parameterInfo.ParameterType.GetFriendlyFullName()}'"
                                + " ... cannot continue.");
                            break;
                        }
                        request.ConstructingTypes.Add(parameterInfo.ParameterType);
                        bool argumentSuccess
                            = ServiceConstructorMethods.invokeMember(
                                  ServiceConstructorMethods.findConstructors(
                                      parameterInfo.ParameterType,
                                      requireConstructorAttributes,
                                      constructorAttributeTypes,
                                      request.TraceStack),
                                  false,
                                  null,
                                  out object argumentResult,
                                  request,
                                  serviceProvider,
                                  instanceProvider,
                                  true,
                                  requireConstructorAttributes,
                                  constructorAttributeTypes,
                                  true);
                        request.ConstructingTypes.Remove(parameterInfo.ParameterType);
                        if (argumentSuccess)
                        {
                            arguments.Add(argumentResult);
                            continue;
                        }
                    }
                    if (parameterInfo.HasDefaultValue)
                    {
                        request.TraceStack.Add(
                            $"Parameter '{parameterInfo.ParameterType.GetFriendlyFullName()}' has default value.");
                        arguments.Add(parameterInfo.DefaultValue);
                    }
                    else
                    {
                        break;
                    }
                }
                if ((arguments.Count != parameters.Length) ||
                    (isMethod
                                                                ? !ServiceConstructorMethods.tryInvokeMethod(
                         methodTarget,
                         (MethodInfo)methodBase,
                         arguments.ToArray(),
                         request.TraceStack)
                                                                : !ServiceConstructorMethods.tryInvokeConstructor(
                         (ConstructorInfo)methodBase,
                         arguments.ToArray(),
                         out newInstance,
                         request.TraceStack)))
                {
                    continue;
                }
                request.Dependencies.TryAddRange(
                    methodBase.DeclaringType,
                    parameters.Select(parameter => parameter.ParameterType));
                success = true;
                break;
            }
            if (isRecursed)
            {
                return(success);
            }
            if (success)
            {
                if (request.Logger.IsVerbose())
                {
                    request.Logger.Verbose(GetTraceMessage());
                }
            }
            else
            {
                if (request.Logger.IsInfo())
                {
                    request.Logger.Info(GetTraceMessage());
                }
            }
            string GetTraceMessage()
            {
                string        separator = $"{Environment.NewLine}    ";
                StringBuilder sb        = request.TraceStack.ToConcatenatedString(null, separator);

                if (sb.Length != 0)
                {
                    sb.Insert(0, "    ");
                }
                return(sb.ToString());
            }

            return(success);
        }