/// <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}" ); }