private MethodDefinition ImplementInterfaceMethod(TypeDefinition typeDefinition, Type interfaceType, IImplementInterfaceAspect aspect, FieldDefinition aspectField, ImplementationInfo.Method methodImplementationInfo) { var interfaceMethod = methodImplementationInfo.InterfaceMethod; var aspectMethod = methodImplementationInfo.AspectMethod; var interfaceMethodRef = ModuleDefinition.ImportReference(interfaceMethod); var aspectMethodDef = ModuleDefinition.ImportReference(aspectMethod).Resolve(); ModuleWeaver.LogInfo($"Implementing method {aspectMethod.Name} in {typeDefinition.FullName}"); // Creates a new method that will proxy to the "original" method. // The interfaces are always explicitly implemented, so that we don't have problems with names collisions var newMethodAttrs = Mono.Cecil.MethodAttributes.Private | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.NewSlot | Mono.Cecil.MethodAttributes.Virtual | Mono.Cecil.MethodAttributes.Final; var newMethodName = $"{interfaceType.Namespace}.{interfaceType.Name}.{interfaceMethod.Name}";// GetUniqueMethodName(typeDefinition, aspectMethod.Name); var newMethodDefinition = new MethodDefinition(newMethodName, newMethodAttrs, ModuleWeaver.TypeSystem.VoidReference); typeDefinition.Methods.Add(newMethodDefinition); newMethodDefinition.Overrides.Add(interfaceMethodRef); // This is what makes the implementation "explicit" newMethodDefinition.CallingConvention = aspectMethodDef.CallingConvention; newMethodDefinition.ExplicitThis = aspectMethodDef.ExplicitThis; newMethodDefinition.HasThis = aspectMethodDef.HasThis; newMethodDefinition.CopyGenericParameters(aspectMethodDef.GenericParameters); newMethodDefinition.ReturnType = ResolveTypeReference(aspectMethod.ReturnType, newMethodDefinition.GenericParameters); foreach (var parameter in aspectMethod.GetParameters()) { var newParameter = new ParameterDefinition(parameter.Name, ParameterAttributes.None, ResolveTypeReference(parameter.ParameterType, newMethodDefinition.GenericParameters)); newParameter.IsIn = parameter.IsIn; newParameter.IsLcid = parameter.IsLcid; newParameter.IsOptional = parameter.IsOptional; newParameter.IsOut = parameter.IsOut; newParameter.IsReturnValue = parameter.IsRetval; // respect parameters with "params" modifier if (parameter.CustomAttributes.Any(attr => attr.AttributeType == typeof(ParamArrayAttribute))) { var ctor = typeof(ParamArrayAttribute).GetConstructor(Type.EmptyTypes); var attr = new CustomAttribute(ModuleDefinition.ImportReference(ctor)); newParameter.CustomAttributes.Add(attr); } newMethodDefinition.Parameters.Add(newParameter); } // Writes the "code" of the new method // This will simply retrieve the aspect instance from the private field created in "InitializeAspectsFields" // and then call the corresponding method on that instance var variableObj = new VariableDefinition(ModuleDefinition.ImportReference(interfaceType)); newMethodDefinition.Body.InitLocals = true; newMethodDefinition.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); newMethodDefinition.Body.Instructions.Add(Instruction.Create(OpCodes.Ldfld, aspectField)); newMethodDefinition.Body.Instructions.Add(Instruction.Create(OpCodes.Castclass, variableObj.VariableType)); foreach (var p in newMethodDefinition.Parameters) { newMethodDefinition.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, p)); } if (interfaceMethodRef.HasGenericParameters) { interfaceMethodRef = interfaceMethodRef.MakeGenericInstanceMethod(newMethodDefinition.GenericParameters.ToArray()); } newMethodDefinition.Body.Instructions.Add(Instruction.Create(OpCodes.Callvirt, interfaceMethodRef)); newMethodDefinition.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); return(newMethodDefinition); }
private PropertyDefinition ImplementInterfaceProperty(TypeDefinition typeDefinition, Type interfaceType, IImplementInterfaceAspect aspect, FieldDefinition aspectField, ImplementationInfo.Property propertyImplementationInfo) { var propertyInfo = propertyImplementationInfo.PropertyInfo; var interfaceGetter = propertyImplementationInfo.InterfaceGetter; var interfaceSetter = propertyImplementationInfo.InterfaceSetter; var aspectGetter = propertyImplementationInfo.AspectGetter; var aspectSetter = propertyImplementationInfo.AspectSetter; var newPropertyDefinition = new PropertyDefinition(propertyInfo.Name, PropertyAttributes.None, ModuleDefinition.ImportReference(propertyInfo.PropertyType)); newPropertyDefinition.IsSpecialName = (propertyInfo.Attributes & System.Reflection.PropertyAttributes.SpecialName) == System.Reflection.PropertyAttributes.SpecialName; newPropertyDefinition.IsRuntimeSpecialName = (propertyInfo.Attributes & System.Reflection.PropertyAttributes.RTSpecialName) == System.Reflection.PropertyAttributes.RTSpecialName; newPropertyDefinition.HasDefault = (propertyInfo.Attributes & System.Reflection.PropertyAttributes.HasDefault) == System.Reflection.PropertyAttributes.HasDefault; if (aspectGetter != null) { var getter = ImplementInterfaceMethod(typeDefinition, interfaceType, aspect, aspectField, new ImplementationInfo.Method(interfaceGetter, aspectGetter)); newPropertyDefinition.GetMethod = getter; } if (aspectSetter != null) { var setter = ImplementInterfaceMethod(typeDefinition, interfaceType, aspect, aspectField, new ImplementationInfo.Method(interfaceSetter, aspectSetter)); newPropertyDefinition.SetMethod = setter; } typeDefinition.Properties.Add(newPropertyDefinition); return(newPropertyDefinition); }
private void ImplementInterface(TypeDefinition typeDefinition, Type interfaceType, IImplementInterfaceAspect aspect, FieldDefinition aspectField) { // Ignores the "IImplementInterfaceAspect" interface that serves only as a marker interface if (interfaceType == typeof(IImplementInterfaceAspect)) { return; } // Ignores the "_Attribute" interface that is automatically implemented by all attributes if (interfaceType.FullName == "System.Runtime.InteropServices._Attribute") { return; } ModuleWeaver.LogInfo($"Implementing interface {interfaceType.FullName} on {typeDefinition.FullName}"); var implementationInfo = GetImplementationInfo(aspect.GetType(), interfaceType); typeDefinition.Interfaces.Add(new InterfaceImplementation(ModuleDefinition.ImportReference(interfaceType))); foreach (var item in implementationInfo) { if (item.Type == ImplementationInfo.Types.Method) { ImplementInterfaceMethod(typeDefinition, interfaceType, aspect, aspectField, item as ImplementationInfo.Method); } else if (item.Type == ImplementationInfo.Types.Property) { ImplementInterfaceProperty(typeDefinition, interfaceType, aspect, aspectField, item as ImplementationInfo.Property); } } }