/// <summary>
        /// Constructs the implementations for all properties.
        /// </summary>
        /// <param name="pipeline">The implementation pipeline that consumes the methods.</param>
        /// <param name="classType">The base class of the type to generator properties for.</param>
        /// <param name="interfaceTypes">The interfaces where the properties originate.</param>
        /// <exception cref="InvalidOperationException">
        /// Thrown if any property is declared as partially abstract.
        /// </exception>
        private void ConstructProperties
        (
            [NotNull] ImplementationPipeline pipeline,
            [NotNull] Type classType,
            [NotNull] params Type[] interfaceTypes
        )
        {
            var symbolTransformer = SymbolTransformer.Default;
            var properties        = new List <PipelineWorkUnit <IntrospectivePropertyInfo> >();

            foreach (var interfaceType in interfaceTypes)
            {
                foreach (var property in interfaceType.GetProperties())
                {
                    var targetProperty = property;

                    // Skip properties with a managed implementation
                    var baseClassProperty = classType.GetProperty(property.Name, property.PropertyType);
                    if (!(baseClassProperty is null))
                    {
                        var isFullyManaged = !baseClassProperty.GetGetMethod().IsAbstract&&
                                             !baseClassProperty.GetSetMethod().IsAbstract;

                        if (isFullyManaged)
                        {
                            continue;
                        }

                        var isPartiallyAbstract = baseClassProperty.GetGetMethod().IsAbstract ^
                                                  baseClassProperty.GetSetMethod().IsAbstract;

                        if (isPartiallyAbstract)
                        {
                            throw new InvalidOperationException
                                  (
                                      "Properties with overriding managed implementations may not be partially managed."
                                  );
                        }

                        targetProperty = baseClassProperty;
                    }

                    var definition = new IntrospectivePropertyInfo(targetProperty);
                    properties.Add
                    (
                        new PipelineWorkUnit <IntrospectivePropertyInfo>
                        (
                            definition,
                            symbolTransformer.GetTransformedSymbol(interfaceType, definition),
                            Options
                        )
                    );
                }
            }

            pipeline.ConsumePropertyDefinitions(properties);
        }
        /// <summary>
        /// Constructs the implementations for all properties.
        /// </summary>
        /// <param name="pipeline">The implementation pipeline that consumes the methods.</param>
        /// <param name="classType">The base class of the type to generator properties for.</param>
        /// <param name="interfaceTypes">The interfaces where the properties originate.</param>
        /// <exception cref="InvalidOperationException">
        /// Thrown if any property is declared as partially abstract.
        /// </exception>
        private void ConstructProperties
        (
            [NotNull] ImplementationPipeline pipeline,
            [NotNull] Type classType,
            [NotNull] params Type[] interfaceTypes
        )
        {
            var constructedProperties = new List <IntrospectivePropertyInfo>();

            var symbolTransformer = SymbolTransformer.Default;
            var properties        = new List <PipelineWorkUnit <IntrospectivePropertyInfo> >();

            foreach (var interfaceType in interfaceTypes)
            {
                foreach (var property in interfaceType.GetProperties().Select(p => new IntrospectivePropertyInfo(p)))
                {
                    var targetProperty = property;

                    // Skip methods that were already constructed - happens with inherited interfaces and multiple
                    // identical definitions
                    if (constructedProperties.Any(p => p.HasSameSignatureAs(property)))
                    {
                        continue;
                    }

                    // Skip properties with a managed implementation
                    var baseClassProperty = classType.GetProperty(property.Name, property.PropertyType);
                    if (!(baseClassProperty is null))
                    {
                        var isFullyManaged = !baseClassProperty.GetGetMethod().IsAbstract&&
                                             !baseClassProperty.GetSetMethod().IsAbstract;

                        if (isFullyManaged)
                        {
                            continue;
                        }

                        var isPartiallyAbstract = baseClassProperty.GetGetMethod().IsAbstract ^
                                                  baseClassProperty.GetSetMethod().IsAbstract;

                        if (isPartiallyAbstract)
                        {
                            throw new InvalidOperationException
                                  (
                                      "Properties with overriding managed implementations may not be partially managed."
                                  );
                        }

                        targetProperty = new IntrospectivePropertyInfo(baseClassProperty);
                    }

                    properties.Add
                    (
                        new PipelineWorkUnit <IntrospectivePropertyInfo>
                        (
                            targetProperty,
                            symbolTransformer.GetTransformedSymbol(interfaceType, targetProperty),
                            Options
                        )
                    );

                    constructedProperties.Add(targetProperty);
                }
            }

            pipeline.ConsumePropertyDefinitions(properties);
        }