/// <summary> /// Weaves the interface. /// What we do here is: /// - creating a class (which is named after the interface name) /// - this class implements all interface members /// - all members invoke Invocation.ProcessInterfaceMethod /// </summary> /// <param name="moduleDefinition">The module definition.</param> /// <param name="interfaceType">Type of the interface.</param> /// <param name="context">The context.</param> private void WeaveInterface(ModuleDefMD moduleDefinition, TypeDef interfaceType, WeavingContext context) { var importedInterfaceType = moduleDefinition.Import(interfaceType); Logging.WriteDebug("Weaving interface '{0}'", interfaceType.FullName); TypeDef implementationType; TypeDef advisedInterfaceType; lock (moduleDefinition) { // ensure we're creating the interface only once var implementationTypeName = GetImplementationTypeName(interfaceType.Name); var implementationTypeNamespace = interfaceType.Namespace; if (moduleDefinition.GetTypes().Any(t => t.Namespace == implementationTypeNamespace && t.Name == implementationTypeName)) { return; } // now, create the implementation type var typeAttributes = (InjectAsPrivate ? TypeAttributes.NotPublic : TypeAttributes.Public) | TypeAttributes.Class | TypeAttributes.BeforeFieldInit; advisedInterfaceType = TypeResolver.Resolve(moduleDefinition, typeof(AdvisedInterface)); // TODO: this should work using TypeImporter.Import var advisedInterfaceTypeReference = moduleDefinition.Import(advisedInterfaceType); implementationType = new TypeDefUser(implementationTypeNamespace, implementationTypeName, advisedInterfaceTypeReference) { Attributes = typeAttributes }; implementationType.Interfaces.Add(new InterfaceImplUser(importedInterfaceType)); lock (moduleDefinition) moduleDefinition.Types.Add(implementationType); } // create empty .ctor. This .NET mofo wants it! var baseEmptyConstructor = moduleDefinition.SafeImport(advisedInterfaceType.FindConstructors().Single()); const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; var method = new MethodDefUser(".ctor", baseEmptyConstructor.MethodSig, ctorAttributes); method.Body = new CilBody(); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, baseEmptyConstructor)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); implementationType.Methods.Add(method); // create implementation methods foreach (var currentInterfaceType in interfaceType.GetAllInterfaces(TypeResolver)) { foreach (var interfaceMethod in currentInterfaceType.Methods.Where(m => !m.IsSpecialName)) { WeaveInterfaceMethod(interfaceMethod, implementationType, true, context); } // create implementation properties foreach (var interfaceProperty in currentInterfaceType.Properties) { var implementationProperty = new PropertyDefUser(interfaceProperty.Name, interfaceProperty.PropertySig); implementationType.Properties.Add(implementationProperty); if (interfaceProperty.GetMethod != null) { implementationProperty.GetMethod = WeaveInterfaceMethod(interfaceProperty.GetMethod, implementationType, InjectAsPrivate, context); } if (interfaceProperty.SetMethod != null) { implementationProperty.SetMethod = WeaveInterfaceMethod(interfaceProperty.SetMethod, implementationType, InjectAsPrivate, context); } } // create implementation events foreach (var interfaceEvent in currentInterfaceType.Events) { var implementationEvent = new EventDefUser(interfaceEvent.Name, interfaceEvent.EventType); implementationType.Events.Add(implementationEvent); if (interfaceEvent.AddMethod != null) { implementationEvent.AddMethod = WeaveInterfaceMethod(interfaceEvent.AddMethod, implementationType, InjectAsPrivate, context); } if (interfaceEvent.RemoveMethod != null) { implementationEvent.RemoveMethod = WeaveInterfaceMethod(interfaceEvent.RemoveMethod, implementationType, InjectAsPrivate, context); } } } }
internal void ImportDeclarations() { var source = _tm.Source; var target = _tm.Target; if (!_merge) { CopyGenericParameters(source, target); } else if (!Equals(source.GenericParameters, target.GenericParameters)) { throw Context.Error( $"can't merge types with different generic params: {source.FullName} and {target.FullName}"); } var injected = Context.Fire(new NetfuserEvent.InjectMembers(Context, _tm)).Injected; // methods should go first, because if other members' names clash, it's easy to change their name // but if we import field "a" and then we get method "a" with hundreds of virtual and interface relatives, we have a problem foreach (var sourceMethod in source.Methods.Concat(injected.OfType <MethodDef>())) { MethodDef result = new MethodDefUser(sourceMethod.Name, Importer.Import(sourceMethod.MethodSig), sourceMethod.ImplAttributes, sourceMethod.Attributes); result = Context.Fire(new NetfuserEvent.CreateMethod(Context, sourceMethod, _tm) { Target = result }).Target; target.Methods.Add(result); _methods.Add(Tuple.Create(sourceMethod, result)); } foreach (var sourceField in source.Fields.Concat(injected.OfType <FieldDef>())) { FieldDef result = new FieldDefUser(sourceField.Name, Importer.Import(sourceField.FieldSig), sourceField.Attributes) { FieldOffset = sourceField.FieldOffset }; result = Context.Fire(new NetfuserEvent.CreateField(Context, sourceField, _tm) { Target = result }).Target; target.Fields.Add(result); _fields.Add(Tuple.Create(sourceField, result)); } foreach (var sourceProperty in source.Properties.Concat(injected.OfType <PropertyDef>())) { PropertyDef result = new PropertyDefUser(sourceProperty.Name, Importer.Import(sourceProperty.PropertySig), sourceProperty.Attributes); result = Context.Fire(new NetfuserEvent.CreateProperty(Context, sourceProperty, _tm) { Target = result }) .Target; target.Properties.Add(result); _properties.Add(Tuple.Create(sourceProperty, result)); } foreach (var sourceEvent in source.Events.Concat(injected.OfType <EventDef>())) { EventDef result = new EventDefUser(sourceEvent.Name, Importer.Import(sourceEvent.EventType), sourceEvent.Attributes); result = Context.Fire(new NetfuserEvent.CreateEvent(Context, sourceEvent, _tm) { Target = result }).Target; target.Events.Add(result); _events.Add(Tuple.Create(sourceEvent, result)); } }