/// <summary>
        /// Gets or creates the convention builder for the specified controller.
        /// </summary>
        /// <param name="controllerType">The <see cref="Type">type</see> of controller to build conventions for.</param>
        /// <returns>A new or existing <see cref="ODataControllerQueryOptionsConventionBuilder"/>.</returns>
        public virtual ODataControllerQueryOptionsConventionBuilder Controller(Type controllerType)
        {
            if (controllerType == null)
            {
                throw new ArgumentNullException(nameof(controllerType));
            }

            var key = GetKey(controllerType);

            if (!ConventionBuilders.TryGetValue(key, out var builder))
            {
                var newBuilder = new ODataControllerQueryOptionsConventionBuilder(controllerType);
                ConventionBuilders[key] = newBuilder;
                return(newBuilder);
            }

            if (builder is ODataControllerQueryOptionsConventionBuilder typedBuilder)
            {
                return(typedBuilder);
            }

            throw new InvalidOperationException(SR.ConventionStyleMismatch.FormatDefault(key.Name));
        }
        /// <summary>
        /// Applies the defined OData query option conventions to the specified API description.
        /// </summary>
        /// <param name="apiDescriptions">The <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiDescription">API descriptions</see>
        /// to apply configured conventions to.</param>
        /// <param name="queryOptionSettings">The <see cref="ODataQueryOptionSettings">settings</see> used to apply OData query option conventions.</param>
        public virtual void ApplyTo(IEnumerable <ApiDescription> apiDescriptions, ODataQueryOptionSettings queryOptionSettings)
        {
            if (apiDescriptions == null)
            {
                throw new ArgumentNullException(nameof(apiDescriptions));
            }

            var conventions = new Dictionary <TypeInfo, IODataQueryOptionsConvention>();

            foreach (var description in apiDescriptions)
            {
                var controller = GetController(description);

                if (!conventions.TryGetValue(controller, out var convention))
                {
                    if (!controller.IsODataController() && !IsODataLike(description))
                    {
                        continue;
                    }

                    if (!ConventionBuilders.TryGetValue(controller, out var builder))
                    {
                        builder = new ODataControllerQueryOptionsConventionBuilder(controller);
                    }

                    convention = builder.Build(queryOptionSettings);
                    conventions.Add(controller, convention);
                }

                convention.ApplyTo(description);

                for (var i = 0; i < Conventions.Count; i++)
                {
                    Conventions[i].ApplyTo(description);
                }
            }
        }
        /// <summary>
        /// Gets or creates the convention builder for the specified controller.
        /// </summary>
        /// <typeparam name="TController">The <see cref="Type">type</see> of controller to build conventions for.</typeparam>
        /// <returns>A new or existing <see cref="ODataControllerQueryOptionsConventionBuilder{T}"/>.</returns>
        public virtual ODataControllerQueryOptionsConventionBuilder <TController> Controller <TController>()
            where TController : notnull
#if WEBAPI
#pragma warning disable SA1001 // Commas should be spaced correctly
        , IHttpController
#pragma warning restore SA1001 // Commas should be spaced correctly
#endif
        {
            var key = GetKey(typeof(TController));

            if (!ConventionBuilders.TryGetValue(key, out var builder))
            {
                var newBuilder = new ODataControllerQueryOptionsConventionBuilder <TController>();
                ConventionBuilders[key] = newBuilder;
                return(newBuilder);
            }

            if (builder is ODataControllerQueryOptionsConventionBuilder <TController> typedBuilder)
            {
                return(typedBuilder);
            }

            throw new InvalidOperationException(SR.ConventionStyleMismatch.FormatDefault(key.Name));
        }