/// <summary>
 ///     Initializes a new instance of the <see cref="ServiceResolveContext"/> class.
 /// </summary>
 /// <param name="resolver">the service resolver using the context</param>
 /// <param name="register">the service register</param>
 /// <param name="constructionMode">the service construction mode for the resolve</param>
 /// <param name="serviceType">the type of the service being resolved</param>
 /// <param name="parentType">the type of the parent</param>
 /// <param name="traceBuilder">
 ///     the trace builder; if <see langword="null"/> a new instance will be created.
 /// </param>
 /// <exception cref="ArgumentNullException">
 ///     thrown if the specified <paramref name="resolver"/> is <see langword="null"/>.
 /// </exception>
 /// <exception cref="ArgumentNullException">
 ///     thrown if the specified <paramref name="register"/> is <see langword="null"/>.
 /// </exception>
 /// <exception cref="ArgumentNullException">
 ///     thrown if the specified <paramref name="serviceType"/> is <see langword="null"/>.
 /// </exception>
 public ServiceResolveContext(IServiceResolver resolver, IServiceRegister register,
                              ServiceConstructionMode constructionMode, Type serviceType, Type parentType = null,
                              TraceBuilder traceBuilder = null)
 {
     ParentType       = parentType;
     ConstructionMode = GetServiceConstructionMode(constructionMode, resolver);
     Resolver         = resolver ?? throw new ArgumentNullException(nameof(resolver));
     Register         = register ?? throw new ArgumentNullException(nameof(register));
     ServiceType      = serviceType ?? throw new ArgumentNullException(nameof(serviceType));
     TraceBuilder     = traceBuilder ?? new TraceBuilder();
 }
        private static ServiceConstructionMode GetServiceConstructionMode(ServiceConstructionMode mode,
                                                                          IServiceResolver resolver, ServiceResolveContext parentContext = null)
        {
            // check if the mode is parent and the parent context is available
            if (mode == ServiceConstructionMode.Parent && parentContext != null)
            {
                return(parentContext.ConstructionMode);
            }

            // check if not the default mode is used
            if (mode != ServiceConstructionMode.Default)
            {
                // use selected mode
                return(mode);
            }

            // use default construction mode
            return(resolver.ServiceConstructionMode);
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="ServiceResolveContext"/> of the
        ///     specified <paramref name="parentContext"/>.
        /// </summary>
        /// <remarks>The depth automatically increases.</remarks>
        /// <param name="parentContext">the parent context to take the data from</param>
        /// <param name="constructionMode"></param>
        /// <param name="serviceType">the type of the new service being resolved</param>
        /// <exception cref="ArgumentNullException">
        ///     thrown if the specified <paramref name="parentContext"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     thrown if the specified <paramref name="serviceType"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///     thrown if the maximum service resolve depth was exceeded.
        /// </exception>
        public ServiceResolveContext(ServiceResolveContext parentContext, ServiceConstructionMode constructionMode,
                                     Type serviceType)
        {
            if (parentContext is null)
            {
                throw new ArgumentNullException(nameof(parentContext));
            }

            ParentType       = parentContext.ServiceType;
            Resolver         = parentContext.Resolver;
            Register         = parentContext.Register;
            ServiceType      = serviceType;
            ConstructionMode = GetServiceConstructionMode(constructionMode, parentContext.Resolver, parentContext);

            // increase resolve depth and check if it was exceeded
            if ((Depth = parentContext.Depth + 1) >= parentContext.Resolver.MaximumDepth)
            {
                throw new InvalidOperationException($"The maximum service resolve depth ({Depth}) was exceeded.");
            }

#if DEBUG
            TraceBuilder = parentContext.TraceBuilder;
#endif // DEBUG
        }
Esempio n. 4
0
        /// <summary>
        ///     Resolves the matching constructor for the specified
        ///     <paramref name="implementationType"/> with respecting the specified <paramref name="constructionMode"/>.
        /// </summary>
        /// <param name="context">the current resolver context</param>
        /// <param name="availableConstructors">
        ///     an enumerable that enumerates through the available constructors for the specified <paramref name="implementationType"/>.
        /// </param>
        /// <param name="implementationType">
        ///     the type of the service implementation to resolve the constructor for
        /// </param>
        /// <param name="constructionMode">the service construction mode.</param>
        /// <returns>the constructor chosen fro the specified <paramref name="implementationType"/></returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     thrown if the specified <paramref name="constructionMode"/> is unsupported or not
        ///     defined in the <see cref="ServiceConstructionMode"/> enumeration.
        /// </exception>
        /// <exception cref="ResolverException">
        ///     thrown if no passable constructor was found for the specified <paramref name="implementationType"/>
        /// </exception>
        public static ConstructorInfo ResolveConstructor(ServiceResolveContext context,
                                                         IEnumerable <ConstructorInfo> availableConstructors, Type implementationType,
                                                         ServiceConstructionMode constructionMode = ServiceConstructionMode.Mixed)
        {
            // check if no constructors are available
            if (!availableConstructors.Any())
            {
                return(null);
            }

            // check whether the mode is mixed
            if (context.ConstructionMode == ServiceConstructionMode.Mixed)
            {
                // iterate through all constructors
                foreach (var constructor in availableConstructors)
                {
                    // check if the constructor is preferred
#if NET35
                    if (constructor.GetCustomAttributes(true).OfType <PreferConstructorAttribute>().Any())
#else // NET35
                    if (constructor.GetCustomAttribute <PreferConstructorAttribute>() != null)
#endif // !NET35
                    {
                        // constructor has the attribute
                        return(constructor);
                    }
                }
            }

            // search complexest constructor
            if (context.ConstructionMode == ServiceConstructionMode.PreferComplexConstructor ||
                context.ConstructionMode == ServiceConstructionMode.Mixed)
            {
                // iterate through all available constructors and find the complexest
                var constructor = availableConstructors
#if SUPPORTS_READONLY_COLLECTIONS
                                  .Select(s => new KeyValuePair <ConstructorInfo, IReadOnlyList <ParameterInfo> >(s, s.GetParameters()))
                                  .OrderByDescending(s => s.Value.Count) // order by parameter count (descending)
#else // SUPPORTS_READONLY_COLLECTIONS
                                  .Select(s => new KeyValuePair <ConstructorInfo, ParameterInfo[]>(s, s.GetParameters()))
                                  .OrderByDescending(s => s.Value.Length) // order by parameter count (descending)
#endif // !SUPPORTS_READONLY_COLLECTIONS
                                  .FirstOrDefault(s => CanUseConstructor(context.Register, s.Value));

                // check if no constructor was found
                if (constructor.Key is null)
                {
                    // throw exception: No constructor was found for the type.
                    throw new ResolverException($"Could not find a passable constructor for '{implementationType}'.", context);
                }

                return(constructor.Key);
            }

            // search parameter-less constructor
            if (context.ConstructionMode == ServiceConstructionMode.PreferParameterlessConstructor)
            {
                // iterate through all available constructors and find a parameter-less
                var constructor = availableConstructors.FirstOrDefault(s => s.GetParameters().Length == 0);

                // check if no constructor was found
                if (constructor is null)
                {
                    // throw exception: No parameter-less constructor
                    throw new ResolverException($"Could not find a parameter-less constructor for '{implementationType}'.", context);
                }

                return(constructor);
            }

            // throw exception: Service Construction mode out of range
            throw new ArgumentOutOfRangeException(nameof(constructionMode), constructionMode,
                                                  $"Invalid or unsupported service construction mode: '{constructionMode}'.");
        }