private static void RegisterDecoratorCore(this Container container, Type serviceType,
                                                  Type decoratorType, Predicate <DecoratorPredicateContext> predicate, Lifestyle lifestyle)
        {
            VerifyMethodArguments(container, serviceType, decoratorType, lifestyle);

            var data = new DecoratorExpressionInterceptorData(container, serviceType, decoratorType,
                                                              predicate, lifestyle);

            container.ExpressionBuilt += new DecoratorInterceptor(data).ExpressionBuilt;
        }
        /// <summary>
        /// Ensures that the decorator type that is returned from <paramref name="decoratorTypeFactory"/> is
        /// supplied when the supplied <paramref name="predicate"/> returns <b>true</b> and cached with the given
        /// <paramref name="lifestyle"/>, wrapping the original registered <paramref name="serviceType"/>, by
        /// injecting that service type into the constructor of the decorator type that is returned by the
        /// supplied <paramref name="decoratorTypeFactory"/>.
        /// Multiple decorators may be applied to the same <paramref name="serviceType"/>. Decorators can be
        /// applied to both open, closed, and non-generic service types.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The types returned from the <paramref name="decoratorTypeFactory"/> may be open-generic. The
        /// container will try to fill in the generic parameters based on the resolved service type.
        /// </para>
        /// <para>
        /// The <b>RegisterOpenGenericDecorator</b> method works by hooking onto the container's
        /// <see cref="Container.ExpressionBuilt">ExpressionBuilt</see> event. This event fires after the
        /// <see cref="Container.ResolveUnregisteredType">ResolveUnregisteredType</see> event, which allows
        /// decoration of types that are resolved using unregistered type resolution. The
        /// <see cref="OpenGenericRegistrationExtensions.RegisterOpenGeneric(Container,Type,Type,Lifestyle)">RegisterOpenGeneric</see>
        /// extension method, for instance, hooks onto the <b>ResolveUnregisteredType</b>. This allows you to
        /// use <b>RegisterOpenGenericDecorator</b> on the same service type as <b>RegisterOpenGeneric</b>.
        /// </para>
        /// <para>
        /// Multiple decorators can be applied to the same service type. The order in which they are registered
        /// is the order they get applied in. This means that the decorator that gets registered first, gets
        /// applied first, which means that the next registered decorator, will wrap the first decorator, which
        /// wraps the original service type.
        /// </para>
        /// <para>
        /// Constructor injection will be used on that type, and although it may have many constructor
        /// arguments, it must have exactly one argument of the type of <paramref name="serviceType"/>, or an
        /// argument of type <see cref="Func{TResult}"/> where <b>TResult</b> is <paramref name="serviceType"/>.
        /// An exception will be thrown when this is not the case.
        /// </para>
        /// <para>
        /// The type returned from <paramref name="decoratorTypeFactory"/> may have a constructor with an
        /// argument of type <see cref="Func{T}"/> where <b>T</b> is <paramref name="serviceType"/>. In this
        /// case, the framework will not inject the decorated <paramref name="serviceType"/> itself into the
        /// decorator instance, but it will inject a <see cref="Func{T}"/> that allows
        /// creating instances of the decorated type, according to the lifestyle of that type. This enables
        /// more advanced scenarios, such as executing the decorated types on a different thread, or executing
        /// decorated instance within a certain scope (such as a lifetime scope).
        /// </para>
        /// </remarks>
        /// <example>
        /// The following is an example of the registration of a decorator through the factory delegate:
        /// <code lang="cs"><![CDATA[
        /// container.Register<ICommandHandler<MoveCustomerCommand>, MoveCustomerCommandHandler>();
        ///
        /// container.RegisterDecorator(
        ///     typeof(ICommandHandler<>),
        ///     context => typeof(LoggingCommandHandler<,>).MakeGenericType(
        ///         typeof(LoggingCommandHandler<,>).GetGenericArguments().First(),
        ///         context.ImplementationType),
        ///     Lifestyle.Transient,
        ///     context => true);
        ///
        /// var handler = container.GetInstance<ICommandHandler<MoveCustomerCommand>>();
        ///
        /// Assert.IsInstanceOfType(handler,
        ///     typeof(LoggingCommandHandler<MoveCustomerCommand, MoveCustomerCommandHandler>));
        ///
        /// ]]></code>
        /// The code above allows a generic <b>LoggingCommandHandler&lt;TCommand, TImplementation&gt;</b> to
        /// be applied to command handlers, where the second generic argument will be filled in using the
        /// contextual information.
        /// </example>
        /// <param name="container">The container to make the registrations in.</param>
        /// <param name="serviceType">The definition of the open generic service type that will
        /// be wrapped by the decorator type returned by the supplied <paramref name="decoratorTypeFactory"/>.</param>
        /// <param name="decoratorTypeFactory">A factory that allows building Type objects that define the
        /// decorators to inject, based on the given contextual information. The delegate is allowed to return
        /// open-generic types.</param>
        /// <param name="lifestyle">The lifestyle that specifies how the returned decorator will be cached.</param>
        /// <param name="predicate">The predicate that determines whether the decorator must be applied to a
        /// service type.</param>
        /// <exception cref="ArgumentNullException">Thrown when one of the arguments is a null reference.</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="serviceType"/> is not
        /// an open generic type.</exception>
        public static void RegisterDecorator(this Container container, Type serviceType,
                                             Func <DecoratorPredicateContext, Type> decoratorTypeFactory, Lifestyle lifestyle,
                                             Predicate <DecoratorPredicateContext> predicate)
        {
            Requires.IsNotNull(container, "container");
            Requires.IsNotNull(serviceType, "serviceType");
            Requires.IsNotNull(decoratorTypeFactory, "decoratorTypeFactory");
            Requires.IsNotNull(lifestyle, "lifestyle");
            Requires.IsNotNull(predicate, "predicate");

            var data = new DecoratorExpressionInterceptorData(container, serviceType, null,
                                                              predicate, lifestyle, decoratorTypeFactory);

            container.ExpressionBuilt += new DecoratorInterceptor(data).ExpressionBuilt;
        }