/// <summary>
        ///     Add command modules from an <see cref="Assembly"/>.
        /// </summary>
        /// <param name="assembly">The <see cref="Assembly"/> containing command modules.</param>
        /// <param name="services">The <see cref="IServiceProvider"/> for your dependency injection solution if using one; otherwise, pass <c>null</c>.</param>
        /// <returns>
        ///     A task that represents the asynchronous operation for adding the command modules. The task result
        ///     contains an enumerable collection of modules added.
        /// </returns>
        public async Task <IEnumerable <ModuleInfo> > AddModulesAsync(Assembly assembly, IServiceProvider services)
        {
            services = services ?? EmptyServiceProvider.Instance;

            await _moduleLock.WaitAsync().ConfigureAwait(false);

            try
            {
                var types = await ModuleClassBuilder.SearchAsync(assembly, this).ConfigureAwait(false);

                var moduleDefs = await ModuleClassBuilder.BuildAsync(types, this, services).ConfigureAwait(false);

                foreach (var info in moduleDefs)
                {
                    _typedModuleDefs[info.Key] = info.Value;
                    LoadModuleInternal(info.Value);
                }

                return(moduleDefs.Select(x => x.Value).ToImmutableArray());
            }
            finally
            {
                _moduleLock.Release();
            }
        }
        /// <summary>
        ///     Adds a command module from a <see cref="Type" />.
        /// </summary>
        /// <param name="type">The type of module.</param>
        /// <param name="services">The <see cref="IServiceProvider" /> for your dependency injection solution if using one; otherwise, pass <c>null</c> .</param>
        /// <exception cref="ArgumentException">This module has already been added.</exception>
        /// <exception cref="InvalidOperationException">
        /// The <see cref="ModuleInfo"/> fails to be built; an invalid type may have been provided.
        /// </exception>
        /// <returns>
        ///     A task that represents the asynchronous operation for adding the module. The task result contains the
        ///     built module.
        /// </returns>
        public async Task <ModuleInfo> AddModuleAsync(Type type, IServiceProvider services)
        {
            services = services ?? EmptyServiceProvider.Instance;

            await _moduleLock.WaitAsync().ConfigureAwait(false);

            try
            {
                var typeInfo = type.GetTypeInfo();

                if (_typedModuleDefs.ContainsKey(type))
                {
                    throw new ArgumentException("This module has already been added.");
                }

                var module = (await ModuleClassBuilder.BuildAsync(this, services, typeInfo).ConfigureAwait(false)).FirstOrDefault();

                if (module.Value == default(ModuleInfo))
                {
                    throw new InvalidOperationException($"Could not build the module {type.FullName}, did you pass an invalid type?");
                }

                _typedModuleDefs[module.Key] = module.Value;

                return(LoadModuleInternal(module.Value));
            }
            finally
            {
                _moduleLock.Release();
            }
        }