/// <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 normal methods.
        /// </summary>
        /// <param name="pipeline">The implementation pipeline that consumes the methods.</param>
        /// <param name="classType">The base class of the type to generate methods for.</param>
        /// <param name="interfaceTypes">The interfaces where the methods originate.</param>
        private void ConstructMethods
        (
            [NotNull] ImplementationPipeline pipeline,
            [NotNull] Type classType,
            [NotNull] params Type[] interfaceTypes
        )
        {
            var symbolTransformer = SymbolTransformer.Default;
            var methods           = new List <PipelineWorkUnit <IntrospectiveMethodInfo> >();

            foreach (var interfaceType in interfaceTypes)
            {
                foreach (var method in interfaceType.GetIntrospectiveMethods(true))
                {
                    var targetMethod = method;

                    // Skip any property accessor methods
                    if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
                    {
                        continue;
                    }

                    // Skip methods with a managed implementation in the base class
                    var baseClassMethod = classType.GetIntrospectiveMethod
                                          (
                        method.Name,
                        method.ParameterTypes.ToArray()
                                          );

                    if (!(baseClassMethod is null))
                    {
                        if (!baseClassMethod.IsAbstract)
                        {
                            continue;
                        }

                        targetMethod = baseClassMethod;
                    }

                    var definition = pipeline.GenerateDefinitionFromSignature(targetMethod);
                    methods.Add
                    (
                        new PipelineWorkUnit <IntrospectiveMethodInfo>
                        (
                            definition,
                            symbolTransformer.GetTransformedSymbol(interfaceType, definition),
                            Options
                        )
                    );
                }
            }

            pipeline.ConsumeMethodDefinitions(methods);
        }
        /// <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);
        }
        private Type GenerateInterfaceImplementationType
        (
            [NotNull] Type classType,
            [NotNull] params Type[] interfaceTypes
        )
        {
            if (!classType.IsAbstract)
            {
                throw new ArgumentException
                      (
                          "The class to activate must be abstract.",
                          nameof(classType)
                      );
            }

            if (!(classType.IsSubclassOf(typeof(NativeLibraryBase)) || classType == typeof(NativeLibraryBase)))
            {
                throw new ArgumentException
                      (
                          $"The base class must be or derive from {nameof(NativeLibraryBase)}.",
                          nameof(classType)
                      );
            }

            if (!interfaceTypes.Any(i => i.IsInterface))
            {
                throw new ArgumentException
                      (
                          "The interface to activate on the class must be an interface type.",
                          nameof(interfaceTypes)
                      );
            }

            var typeName = GenerateTypeName(classType);

            // Create a new type for the anonymous implementation
            var typeBuilder = _moduleBuilder.DefineType
                              (
                typeName,
                TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed,
                classType,
                interfaceTypes
                              );

            // Now the constructor
            var anonymousConstructor = typeof(NativeLibraryBase)
                                       .GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)
                                       .First
                                       (
                c => c.HasCustomAttribute <AnonymousConstructorAttribute>()
                                       );

            var constructorBuilder = typeBuilder.DefineConstructor
                                     (
                Public | SpecialName | RTSpecialName | HideBySig,
                Standard,
                anonymousConstructor.GetParameters().Select(p => p.ParameterType).ToArray()
                                     );

            constructorBuilder.DefineParameter(1, ParameterAttributes.In, "libraryPath");
            var constructorIL = constructorBuilder.GetILGenerator();

            for (var i = 0; i <= anonymousConstructor.GetParameters().Length; ++i)
            {
                constructorIL.Emit(OpCodes.Ldarg, i);
            }

            constructorIL.Emit(OpCodes.Call, anonymousConstructor);

            var pipeline = new ImplementationPipeline
                           (
                _moduleBuilder,
                typeBuilder,
                constructorIL,
                Options
                           );

            ConstructMethods(pipeline, classType, interfaceTypes);
            ConstructProperties(pipeline, classType, interfaceTypes);

            constructorIL.Emit(OpCodes.Ret);
            return(typeBuilder.CreateTypeInfo());
        }
        /// <summary>
        /// Constructs the implementations for all normal methods.
        /// </summary>
        /// <param name="pipeline">The implementation pipeline that consumes the methods.</param>
        /// <param name="classType">The base class of the type to generate methods for.</param>
        /// <param name="interfaceTypes">The interfaces where the methods originate.</param>
        private void ConstructMethods
        (
            [NotNull] ImplementationPipeline pipeline,
            [NotNull] Type classType,
            [NotNull, ItemNotNull] params Type[] interfaceTypes
        )
        {
            var constructedMethods = new List <IntrospectiveMethodInfo>();

            var symbolTransformer = SymbolTransformer.Default;
            var methods           = new List <PipelineWorkUnit <IntrospectiveMethodInfo> >();

            foreach (var interfaceType in interfaceTypes)
            {
                foreach (var method in interfaceType.GetIntrospectiveMethods(true))
                {
                    var targetMethod = method;

                    // Skip any property accessor methods
                    if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_")))
                    {
                        continue;
                    }

                    // Skip methods that were already constructed - happens with inherited interfaces and multiple
                    // identical definitions
                    var existingMethod = constructedMethods.FirstOrDefault(m => m.HasSameSignatureAs(method));
                    if (!(existingMethod is null))
                    {
                        if (existingMethod.HasSameNativeEntrypointAs(targetMethod))
                        {
                            pipeline.TargetType.DefineMethodOverride
                            (
                                existingMethod.GetWrappedMember(),
                                targetMethod.GetWrappedMember()
                            );

                            continue;
                        }
                    }

                    // Skip methods with a managed implementation in the base class
                    var baseClassMethod = classType.GetIntrospectiveMethod
                                          (
                        method.Name,
                        method.ParameterTypes.ToArray()
                                          );

                    if (!(baseClassMethod is null))
                    {
                        if (!baseClassMethod.IsAbstract)
                        {
                            continue;
                        }
                    }

                    // If we have an existing method at this point, this new method must be created as an explicit
                    // interface implementation. Therefore, we override the method name.
                    IntrospectiveMethodInfo definition;
                    if (!(existingMethod is null))
                    {
                        definition = pipeline.GenerateDefinitionFromSignature
                                     (
                            targetMethod,
                            baseClassMethod,
                            $"{interfaceType.Name}.{targetMethod.Name}"
                                     );
                    }