Example #1
0
        /// <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);
                    }
                }
            }
        }
Example #2
0
        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));
            }
        }