/// <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 }
/// <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}'."); }