private bool TryCreateHandlerDescriptor(ConstructorInfo constructor, IServiceProvider services, out CommandHandlerDescriptor result, ref IDictionary <Type, object> resolvedServices)
        {
            result = null;
            ParameterInfo[] ctorParams   = constructor.GetParameters();
            object[]        paramsValues = new object[ctorParams.Length];
            foreach (ParameterInfo param in ctorParams)
            {
                if (!resolvedServices.TryGetValue(param.ParameterType, out object value))
                {
                    if (ParameterBuilder.TryGetService(param.ParameterType, services, out value))
                    {
                    }
                    else if (ParameterBuilder.TryGetGenericLogger(param.ParameterType, services, out value))
                    {
                    }
                    else if (param.IsOptional)
                    {
                        value = param.HasDefaultValue ? param.DefaultValue : null;
                    }
                    else
                    {
                        return(false);
                    }

                    resolvedServices[param.ParameterType] = value;
                }
                paramsValues[param.Position] = value;
            }
            result = new CommandHandlerDescriptor(constructor, paramsValues);
            return(true);
        }
        /// <inheritdoc/>
        public ICommandsHandlerProviderResult GetCommandHandler(ICommandInstanceDescriptor descriptor, IServiceProvider services)
        {
            Type handlerType = descriptor.GetHandlerType();
            CommandHandlerDescriptor handlerDescriptor = null;

            lock (_lock)
            {
                // check if persistent
                if (_persistentHandlers.TryGetValue(handlerType, out CommandsHandlerProviderResult handler))
                {
                    return(handler);
                }

                // keep resolved services to avoid recreating them in case of multiple constructors
                IDictionary <Type, object> resolvedServices = new Dictionary <Type, object>();

                // if no persistent handler was found, we need to create a new one - check if constructor is known yet
                if (!_knownConstructors.TryGetValue(handlerType, out ConstructorInfo handlerConstructor))
                {
                    // if descriptor not cached, create new one
                    // start with grabbing all constructors
                    IEnumerable <ConstructorInfo> allConstructors = handlerType
                                                                    .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

                    // check if any of the constructors are specifically designated to be used by Commands System
                    IEnumerable <ConstructorInfo> selectedConstructors = allConstructors
                                                                         .Select(ctor => (constructor: ctor, attribute: ctor.GetCustomAttribute <CommandsHandlerConstructorAttribute>(false)))
                                                                         .Where(ctor => ctor.attribute != null)
                                                                         .OrderByDescending(ctor => ctor.attribute.Priority)
                                                                         .ThenByDescending(ctor => ctor.constructor.GetParameters().Length)
                                                                         .Select(ctor => ctor.constructor);

                    // if no explicitly-attributed constructor found, grab all that are public
                    if (!selectedConstructors.Any())
                    {
                        selectedConstructors = allConstructors
                                               .Where(ctor => ctor.IsPublic)
                                               .OrderByDescending(ctor => ctor.GetParameters().Length);
                    }

                    // try to resolve dependencies for each constructor. First one that can be resolved wins
                    foreach (ConstructorInfo ctor in selectedConstructors)
                    {
                        if (TryCreateHandlerDescriptor(ctor, services, out handlerDescriptor, ref resolvedServices))
                        {
                            // cache found descriptor
                            _knownConstructors.Add(handlerType, ctor);
                            handlerConstructor = ctor;
                            break;
                        }
                    }
                    // throw if we didn't find any constructor we can resolve
                    if (handlerDescriptor == null)
                    {
                        throw new InvalidOperationException($"Cannot create descriptor for type {handlerType.FullName} - none of the constructors can have its dependencies resolved");
                    }
                }
                // if constructor is already known, just create a descriptor
                else
                {
                    TryCreateHandlerDescriptor(handlerConstructor, services, out handlerDescriptor, ref resolvedServices);
                }

                // now that we have a descriptor, let's create an instance
                handler = new CommandsHandlerProviderResult(handlerDescriptor, handlerDescriptor.CreateInstance());

                // if it's a persistent instance, store it
                if (handlerDescriptor.IsPersistent())
                {
                    _persistentHandlers.Add(handlerType, handler);
                }

                // finally, return the fresh handler
                return(handler);
            }
        }