private MethodDefinition EnsureOnPropertyChangedMethod() { var type = _catelType.TypeDefinition; MethodDefinition methodDefinition = null; var possibleMethods = type.Methods.Where(definition => definition.Name == "OnPropertyChanged" && definition.HasParameters).ToList(); foreach (var possibleMethod in possibleMethods) { if (string.Equals(possibleMethod.Parameters[0].ParameterType.FullName, _catelType.AdvancedPropertyChangedEventArgsType.FullName)) { methodDefinition = possibleMethod; break; } } var baseOnPropertyChangedInvoker = _catelType.BaseOnPropertyChangedInvoker; if (methodDefinition == null) { var voidType = _msCoreReferenceFinder.GetCoreTypeReference("Void"); methodDefinition = new MethodDefinition("OnPropertyChanged", MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual, type.Module.Import(voidType)); methodDefinition.Parameters.Add(new ParameterDefinition("e", ParameterAttributes.None, _catelType.AdvancedPropertyChangedEventArgsType)); var body = methodDefinition.Body; body.SimplifyMacros(); body.Instructions.Add(Instruction.Create(OpCodes.Nop)); body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); body.Instructions.Add(Instruction.Create(OpCodes.Call, baseOnPropertyChangedInvoker)); body.Instructions.Add(Instruction.Create(OpCodes.Nop)); body.Instructions.Add(Instruction.Create(OpCodes.Ret)); body.OptimizeMacros(); type.Methods.Add(methodDefinition); methodDefinition.MarkAsCompilerGenerated(_msCoreReferenceFinder); } else { // Note: need to replace call to base, otherwise it might skip a call to a just generated base member var body = methodDefinition.Body; var hasReplaced = false; body.SimplifyMacros(); foreach (var instruction in body.Instructions) { if (instruction.OpCode == OpCodes.Call) { var methodReference = instruction.Operand as MethodReference; if ((methodReference != null) && string.Equals(methodReference.Name, baseOnPropertyChangedInvoker.Name)) { instruction.Operand = baseOnPropertyChangedInvoker; hasReplaced = true; } } } body.OptimizeMacros(); if (!methodDefinition.IsMarkedAsGeneratedCode()) { // Don't support this, see CTL-569 return null; } } return methodDefinition; }
private void AddGetXmlSchemaMethod(CatelType catelType) { var catelTypeDefinition = catelType.TypeDefinition; var methodName = GetXmlSchemaMethodName(catelType); var alreadyHandled = (from method in catelTypeDefinition.Methods where method.Name == methodName select method).Any(); if (alreadyHandled) { return; } var getTypeFromHandle = catelTypeDefinition.Module.GetMethod("GetTypeFromHandle"); var importedGetTypeFromHandle = catelTypeDefinition.Module.Import(getTypeFromHandle); var xmlSchemaManager = (TypeDefinition)catelTypeDefinition.Module.FindType("Catel.Core", "Catel.Runtime.Serialization.Xml.XmlSchemaManager"); if (xmlSchemaManager == null) { // Support versions before 3.8 xmlSchemaManager = (TypeDefinition)catelTypeDefinition.Module.FindType("Catel.Core", "Catel.Runtime.Serialization.XmlSchemaManager"); } var getXmlSchemaMethodOnXmlSchemaManager = catelTypeDefinition.Module.Import(xmlSchemaManager.Methods.First(x => x.IsStatic && x.Name == "GetXmlSchema")); //public static XmlQualifiedName GetXmlSchema(XmlSchemaSet schemas) //{ // Type callingType = typeof(int); // return XmlSchemaManager.GetXmlSchema(callingType, schemas); //} var getXmlSchemaMethod = new MethodDefinition(methodName, MethodAttributes.Public | MethodAttributes.Static, catelTypeDefinition.Module.Import(_msCoreReferenceFinder.XmlQualifiedName)); getXmlSchemaMethod.Parameters.Add(new ParameterDefinition("xmlSchemaSet", ParameterAttributes.None, catelTypeDefinition.Module.Import(_msCoreReferenceFinder.XmlSchemaSet))); var ldloc1Instruction = Instruction.Create(OpCodes.Ldloc_1); var instructions = getXmlSchemaMethod.Body.Instructions; instructions.Insert(0, Instruction.Create(OpCodes.Nop), Instruction.Create(OpCodes.Ldtoken, catelTypeDefinition), Instruction.Create(OpCodes.Call, importedGetTypeFromHandle), Instruction.Create(OpCodes.Stloc_0), Instruction.Create(OpCodes.Ldloc_0), Instruction.Create(OpCodes.Ldarg_0), Instruction.Create(OpCodes.Call, getXmlSchemaMethodOnXmlSchemaManager), Instruction.Create(OpCodes.Stloc_1), Instruction.Create(OpCodes.Br_S, ldloc1Instruction), ldloc1Instruction, Instruction.Create(OpCodes.Ret)); getXmlSchemaMethod.Body.InitLocals = true; getXmlSchemaMethod.Body.Variables.Add(new VariableDefinition("callingType", catelTypeDefinition.Module.Import(catelTypeDefinition.Module.FindType("mscorlib", "System.Type")))); getXmlSchemaMethod.Body.Variables.Add(new VariableDefinition(catelTypeDefinition.Module.Import(_msCoreReferenceFinder.XmlQualifiedName))); catelTypeDefinition.Methods.Add(getXmlSchemaMethod); getXmlSchemaMethod.MarkAsCompilerGenerated(_msCoreReferenceFinder); }
private int AddGetValueCall(PropertyDefinition property, FieldReference fieldReference) { FodyEnvironment.LogDebug($"\t\t\t{property.Name} - adding GetValue call"); var genericGetValue = new GenericInstanceMethod(_catelType.GetValueInvoker); foreach (var genericParameter in _catelType.GetValueInvoker.GenericParameters) { genericGetValue.GenericParameters.Add(genericParameter); } genericGetValue.GenericArguments.Add(property.PropertyType.Import()); if (property.GetMethod == null) { var getMethod = new MethodDefinition($"get_{property.Name}", MethodAttributes.Public, property.PropertyType.Import()); property.DeclaringType.Methods.Add(getMethod); getMethod.MarkAsCompilerGenerated(_msCoreReferenceFinder); property.GetMethod = getMethod; } var body = property.GetMethod.Body; body.SimplifyMacros(); var instructions = body.Instructions; instructions.Clear(); var finalIndex = instructions.Insert(0, Instruction.Create(OpCodes.Nop), Instruction.Create(OpCodes.Ldarg_0), Instruction.Create(OpCodes.Ldsfld, fieldReference), Instruction.Create(OpCodes.Call, genericGetValue), Instruction.Create(OpCodes.Ret)); body.OptimizeMacros(); return finalIndex; }
private int AddSetValueCall(PropertyDefinition property, FieldReference fieldReference, bool isReadOnly) { FodyEnvironment.LogDebug($"\t\t\t{property.Name} - adding SetValue call"); //string fieldName = string.Format("{0}Property", property.Name); //var declaringType = property.DeclaringType; //var fieldReference = GetField(declaringType, fieldName); // Writes SetValue(PropertyData propertyName, object value) if (property.SetMethod == null) { var voidType = _msCoreReferenceFinder.GetCoreTypeReference("Void"); var setMethod = new MethodDefinition($"set_{property.Name}", MethodAttributes.Public, property.DeclaringType.Module.Import(voidType)); setMethod.Parameters.Add(new ParameterDefinition(property.PropertyType.Import())); property.DeclaringType.Methods.Add(setMethod); setMethod.MarkAsCompilerGenerated(_msCoreReferenceFinder); property.SetMethod = setMethod; } var finalSetMethod = property.SetMethod; if (isReadOnly) { finalSetMethod.IsPrivate = true; finalSetMethod.IsPublic = false; } var body = property.SetMethod.Body; body.SimplifyMacros(); var instructions = body.Instructions; instructions.Clear(); var instructionsToAdd = new List<Instruction>(); instructionsToAdd.AddRange(new[] { Instruction.Create(OpCodes.Ldarg_0), Instruction.Create(OpCodes.Ldsfld, fieldReference), Instruction.Create(OpCodes.Ldarg_1) }); if (property.PropertyType.IsBoxingRequired(_catelType.SetValueInvoker.Parameters[1].ParameterType)) { instructionsToAdd.Add(Instruction.Create(OpCodes.Box, property.PropertyType.Import())); } instructionsToAdd.Add(Instruction.Create(OpCodes.Call, _catelType.SetValueInvoker)); instructionsToAdd.Add(Instruction.Create(OpCodes.Ret)); var finalIndex = instructions.Insert(0, instructionsToAdd.ToArray()); body.OptimizeMacros(); return finalIndex; }
private void AddChangeNotificationHandlerField(PropertyDefinition property, CatelTypeProperty propertyData) { if (propertyData.ChangeCallbackReference == null) { return; } FodyEnvironment.LogDebug($"\t\t\t{property.Name} - adding On{property.Name}Changed invocation"); var declaringType = property.DeclaringType; string fieldName = GetChangeNotificationHandlerFieldName(property); var handlerType = GetEventHandlerAdvancedPropertyChangedEventArgs(property); var advancedPropertyChangedEventArgsType = property.Module.FindType("Catel.Core", "Catel.Data.AdvancedPropertyChangedEventArgs"); //.field private static class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> CS$<>9__CachedAnonymousMethodDelegate1 var field = new FieldDefinition(fieldName, FieldAttributes.Private | FieldAttributes.Static, declaringType.Module.Import(handlerType)); declaringType.Fields.Add(field); field.MarkAsCompilerGenerated(_msCoreReferenceFinder); //.method private hidebysig static void <.cctor>b__0(object s, class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs e) cil managed //{ // .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() // .maxstack 8 // L_0000: ldarg.0 // L_0001: castclass Catel.Fody.TestAssembly.ModelBaseTest // L_0006: callvirt instance void Catel.Fody.TestAssembly.ModelBaseTest::OnLastNameChanged() // L_000b: nop // L_000c: ret //} var voidType = _msCoreReferenceFinder.GetCoreTypeReference("Void"); var objectType = _msCoreReferenceFinder.GetCoreTypeReference("Object"); string initializationMethodName = GetChangeNotificationHandlerConstructorName(property); var initializationMethod = new MethodDefinition(initializationMethodName, MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, declaringType.Module.Import(voidType)); initializationMethod.Parameters.Add(new ParameterDefinition("s", ParameterAttributes.None, declaringType.Module.Import(objectType))); initializationMethod.Parameters.Add(new ParameterDefinition("e", ParameterAttributes.None, declaringType.Module.Import(advancedPropertyChangedEventArgsType))); var body = initializationMethod.Body; body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldarg_0), Instruction.Create(OpCodes.Castclass, declaringType.MakeGenericIfRequired()), Instruction.Create(OpCodes.Callvirt, propertyData.ChangeCallbackReference), Instruction.Create(OpCodes.Nop), Instruction.Create(OpCodes.Ret)); declaringType.Methods.Add(initializationMethod); initializationMethod.MarkAsCompilerGenerated(_msCoreReferenceFinder); }