public PropertyWeaverBase(CatelType catelType, CatelTypeProperty propertyData, ModuleWeaver moduleWeaver, MsCoreReferenceFinder msCoreReferenceFinder) { _catelType = catelType; _propertyData = propertyData; _moduleWeaver = moduleWeaver; _msCoreReferenceFinder = msCoreReferenceFinder; }
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; var 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.ImportReference(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"); var initializationMethodName = GetChangeNotificationHandlerConstructorName(property); var initializationMethod = new MethodDefinition(initializationMethodName, MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, declaringType.Module.ImportReference(voidType)); initializationMethod.Parameters.Add(new ParameterDefinition("s", ParameterAttributes.None, declaringType.Module.ImportReference(objectType))); initializationMethod.Parameters.Add(new ParameterDefinition("e", ParameterAttributes.None, declaringType.Module.ImportReference(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); }
private void AddChangeNotificationHandlerField(PropertyDefinition property, CatelTypeProperty propertyData) { if (propertyData.ChangeCallbackReference is null) { return; } FodyEnvironment.WriteDebug($"\t\t\t{property.Name} - adding On{property.Name}Changed invocation"); switch (_catelType.Version) { case CatelVersion.v5: AddChangeNotificationHandlerField_Catel5(property, propertyData); break; case CatelVersion.v6: AddChangeNotificationHandlerField_Catel6(property, propertyData); break; } }
public ObservableObjectPropertyWeaver(CatelType catelType, CatelTypeProperty propertyData, ModuleWeaver moduleWeaver, MsCoreReferenceFinder msCoreReferenceFinder) : base(catelType, propertyData, moduleWeaver, msCoreReferenceFinder) { }
private List <Instruction> CreateDefaultValueInstructions(CatelTypeProperty propertyData) { var instructions = new List <Instruction>(); var resolvedPropertyType = propertyData.PropertyDefinition.PropertyType.Resolve(); // Default value if (propertyData.DefaultValue is string stringValue) { instructions.Add(Instruction.Create(OpCodes.Ldstr, stringValue)); } else if (propertyData.DefaultValue is bool boolValue) { if (boolValue) { instructions.Add(Instruction.Create(OpCodes.Ldc_I4_1)); } else { instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0)); } } else if (propertyData.DefaultValue is int intValue) { instructions.Add(Instruction.Create(OpCodes.Ldc_I4, intValue)); } else if (propertyData.DefaultValue is long longValue) { if (longValue <= int.MaxValue) { // Note: don't use Ldc_I8 here, although it is a long instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)longValue)); instructions.Add(Instruction.Create(OpCodes.Conv_I8)); } else { instructions.Add(Instruction.Create(OpCodes.Ldc_I8, longValue)); } } else if (propertyData.DefaultValue is float floatValue) { instructions.Add(Instruction.Create(OpCodes.Ldc_R4, floatValue)); } else if (propertyData.DefaultValue is double doubleValue) { instructions.Add(Instruction.Create(OpCodes.Ldc_R8, doubleValue)); } else if (resolvedPropertyType != null && resolvedPropertyType.IsEnum && propertyData.DefaultValue != null) { instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)((CustomAttributeArgument)propertyData.DefaultValue).Value)); } else { instructions.Add(Instruction.Create(OpCodes.Ldnull)); } // Special case: if Nullable<ValueType>, we need to do special things if (propertyData.PropertyDefinition.PropertyType.IsNullableValueType() && propertyData.DefaultValue is null == false) { // IL_0033: ldc.i4.1 // already done above) // IL_0034: newobj instance void valuetype [System.Runtime]System.Nullable`1<bool>::.ctor(!0) var declaringType = (GenericInstanceType)propertyData.PropertyDefinition.PropertyType; var resolvedType = declaringType.Resolve(); resolvedType.FixPrivateCorLibScope(); var ctorDefinition = resolvedType.Constructor(false); var importedCtor = _catelType.TypeDefinition.Module.ImportReference(ctorDefinition); var ctor = importedCtor.MakeHostInstanceGeneric(declaringType.GenericArguments[0]); instructions.Add(Instruction.Create(OpCodes.Newobj, ctor)); } return(instructions); }
private List <Instruction> CreatePropertyRegistration_Catel6(PropertyDefinition property, CatelTypeProperty propertyData) { // Catel v6: // //L_0000: ldstr "FullName" //L_0005: ldtoken string // note that this is the property type //L_000a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) //L_000f: ldnull //L_0010: ldnull //L_0011: ldc.i4.1 //L_0012: call class [Catel.Core]Catel.Data.IPropertyData [Catel.Core]Catel.Data.ModelBase::RegisterProperty<TValue>(string, class [mscorlib]System.Func`1<TValue>, class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.PropertyChangedEventArgs>, bool) //L_0017: stsfld class [Catel.Core]Catel.Data.IPropertyData Catel.Fody.TestAssembly.ViewModelBaseTest::FullNameProperty var instructions = new List <Instruction>(); instructions.AddRange(new[] { Instruction.Create(OpCodes.Ldstr, property.Name), }); instructions.AddRange(CreateDefaultValueInstructions(propertyData)); if (propertyData.ChangeCallbackReference != null) { instructions.AddRange(CreateChangeCallbackReference_Catel6(property)); } else { instructions.Add(Instruction.Create(OpCodes.Ldnull)); } return(instructions); }
private bool AddPropertyRegistration(PropertyDefinition property, CatelTypeProperty propertyData) { var fieldName = $"{property.Name}Property"; var declaringType = property.DeclaringType; var fieldReference = GetFieldReference(declaringType, fieldName, true); if (fieldReference is null) { FodyEnvironment.WriteWarning($"\t\tCannot handle property '{_catelType.Name}.{property.Name}' because backing field is not found"); return(false); } var staticConstructor = declaringType.Constructor(true); var body = staticConstructor.Body; body.SimplifyMacros(); var instructions = body.Instructions; // Always inject before the first try block, or just before the last return statement var instructionToInsert = (from instruction in instructions where instruction.OpCode == OpCodes.Ret select instruction).FirstOrDefault(); var exceptionHandler = body.ExceptionHandlers.FirstOrDefault(); if (exceptionHandler != null) { instructionToInsert = exceptionHandler.TryStart; } var index = (instructionToInsert != null) ? instructions.IndexOf(instructionToInsert) : instructions.Count; var instructionsToInsert = new List <Instruction>(); switch (_catelType.Version) { case CatelVersion.v5: instructionsToInsert.AddRange(CreatePropertyRegistration_Catel5(property, propertyData)); break; case CatelVersion.v6: instructionsToInsert.AddRange(CreatePropertyRegistration_Catel6(property, propertyData)); break; } var registerPropertyInvoker = (propertyData.DefaultValue is null) ? _catelType.RegisterPropertyWithoutDefaultValueInvoker : _catelType.RegisterPropertyWithDefaultValueInvoker; // Fill up the final booleans: // Catel v5: RegisterProperty([0] string name, // [1] Type type, // [2] Func<object> createDefaultValue = null, // [3] EventHandler<AdvancedPropertyChangedEventArgs> propertyChangedEventHandler = null, // [4] bool includeInSerialization = true, // [5] bool includeInBackup = true) // // Catel v6: RegisterProperty<TValue>([0] string name, // [1] Func<TValue> createDefaultValue = null, // [2] EventHandler<APropertyChangedEventArgs> propertyChangedEventHandler = null, // [3] bool includeInSerialization = true, // [4] bool includeInBackup = true) var parameters = registerPropertyInvoker.Parameters.Skip(3).ToList(); var boolCount = 0; for (var i = 0; i < parameters.Count; i++) { var parameter = parameters[i]; if (string.CompareOrdinal(parameter.ParameterType.FullName, _moduleWeaver.TypeSystem.BooleanDefinition.FullName) != 0) { continue; } boolCount++; // includeInBackup == 2nd bool value if (!propertyData.IncludeInBackup && boolCount == 2) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4_0)); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4_1)); } } // Make call to register property generic var finalRegisterPropertyMethod = registerPropertyInvoker; if (registerPropertyInvoker.HasGenericParameters) { var genericRegisterProperty = new GenericInstanceMethod(registerPropertyInvoker); if (registerPropertyInvoker.HasGenericParameters) { foreach (var genericParameter in registerPropertyInvoker.GenericParameters) { genericRegisterProperty.GenericParameters.Add(genericParameter); } genericRegisterProperty.GenericArguments.Add(property.PropertyType.Import(false)); } finalRegisterPropertyMethod = genericRegisterProperty; } instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Call, finalRegisterPropertyMethod), Instruction.Create(OpCodes.Stsfld, fieldReference) }); instructions.Insert(index, instructionsToInsert); body.OptimizeMacros(); return(true); }
public ModelBasePropertyWeaver(CatelType catelType, CatelTypeProperty propertyData, Configuration configuration, ModuleWeaver moduleWeaver, MsCoreReferenceFinder msCoreReferenceFinder) : base(catelType, propertyData, moduleWeaver, msCoreReferenceFinder) { _configuration = configuration; }
public CatelPropertyWeaver(CatelType catelType, CatelTypeProperty propertyData, MsCoreReferenceFinder msCoreReferenceFinder) { _catelType = catelType; _propertyData = propertyData; _msCoreReferenceFinder = msCoreReferenceFinder; }
private bool AddPropertyRegistration(PropertyDefinition property, CatelTypeProperty propertyData) { var fieldName = $"{property.Name}Property"; var declaringType = property.DeclaringType; var fieldReference = GetFieldReference(declaringType, fieldName, true); if (fieldReference == null) { FodyEnvironment.LogWarning($"\t\tCannot handle property '{_catelType.Name}.{property.Name}' because backing field is not found"); return(false); } var staticConstructor = declaringType.Constructor(true); var body = staticConstructor.Body; body.SimplifyMacros(); var instructions = body.Instructions; // Always inject before the first try block, or just before the last return statement var instructionToInsert = (from instruction in instructions where instruction.OpCode == OpCodes.Ret select instruction).FirstOrDefault(); var exceptionHandler = body.ExceptionHandlers.FirstOrDefault(); if (exceptionHandler != null) { instructionToInsert = exceptionHandler.TryStart; } var index = (instructionToInsert != null) ? instructions.IndexOf(instructionToInsert) : instructions.Count; //L_0000: ldstr "FullName" //L_0005: ldtoken string // note that this is the property type //L_000a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) //L_000f: ldnull //L_0010: ldnull //L_0011: ldc.i4.1 //L_0012: call class [Catel.Core]Catel.Data.PropertyData [Catel.Core]Catel.Data.ModelBase::RegisterProperty(string, class [mscorlib]System.Type, class [mscorlib]System.Func`1<object>, class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs>, bool) //L_0017: stsfld class [Catel.Core]Catel.Data.PropertyData Catel.Fody.TestAssembly.ViewModelBaseTest::FullNameProperty var getTypeFromHandle = property.Module.GetMethodAndImport("GetTypeFromHandle"); var instructionsToInsert = new List <Instruction>(); instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Ldstr, property.Name), Instruction.Create(OpCodes.Ldtoken, property.PropertyType.Import()), Instruction.Create(OpCodes.Call, getTypeFromHandle), }); var resolvedPropertyType = propertyData.PropertyDefinition.PropertyType.Resolve(); // Default value if (propertyData.DefaultValue is string) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldstr, (string)propertyData.DefaultValue)); } else if (propertyData.DefaultValue is bool) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (bool)propertyData.DefaultValue ? 1 : 0)); } else if (propertyData.DefaultValue is int) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (int)propertyData.DefaultValue)); } else if (propertyData.DefaultValue is long) { if ((long)propertyData.DefaultValue <= int.MaxValue) { // Note: don't use Ldc_I8 here, although it is a long instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (int)(long)propertyData.DefaultValue)); instructionsToInsert.Add(Instruction.Create(OpCodes.Conv_I8)); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I8, (long)propertyData.DefaultValue)); } } else if (propertyData.DefaultValue is float) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_R4, (float)propertyData.DefaultValue)); } else if (propertyData.DefaultValue is double) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_R8, (double)propertyData.DefaultValue)); } else if (resolvedPropertyType != null && resolvedPropertyType.IsEnum && propertyData.DefaultValue != null) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (int)((CustomAttributeArgument)propertyData.DefaultValue).Value)); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldnull)); } if (propertyData.ChangeCallbackReference != null) { //L_0040: ldsfld class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> Catel.Fody.TestAssembly.ModelBaseTest::CS$<>9__CachedAnonymousMethodDelegate1 //L_0045: brtrue.s L_005a //L_0047: ldnull //L_0048: ldftn void Catel.Fody.TestAssembly.ModelBaseTest::<.cctor>b__0(object, class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs) //L_004e: newobj instance void [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs>::.ctor(object, native int) //L_0053: stsfld class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> Catel.Fody.TestAssembly.ModelBaseTest::CS$<>9__CachedAnonymousMethodDelegate1 //L_0058: br.s L_005a //L_005a: ldsfld class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> Catel.Fody.TestAssembly.ModelBaseTest::CS$<>9__CachedAnonymousMethodDelegate1 var handlerFieldName = GetChangeNotificationHandlerFieldName(property); var handlerConstructorFieldName = GetChangeNotificationHandlerConstructorName(property); var handlerField = GetFieldReference(property.DeclaringType, handlerFieldName, true); var handlerConstructor = GetMethodReference(property.DeclaringType, handlerConstructorFieldName, true); var handlerType = GetEventHandlerAdvancedPropertyChangedEventArgs(property); var importedHandlerType = handlerType.Resolve(); var advancedPropertyChangedEventArgsType = property.Module.FindType("Catel.Core", "Catel.Data.AdvancedPropertyChangedEventArgs"); var handlerTypeConstructor = declaringType.Module.ImportReference(importedHandlerType.Constructor(false)); var genericConstructor = handlerTypeConstructor.MakeHostInstanceGeneric(declaringType.Module.ImportReference(advancedPropertyChangedEventArgsType)); var finalInstruction = Instruction.Create(OpCodes.Ldsfld, handlerField); instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Ldsfld, handlerField), Instruction.Create(OpCodes.Brtrue_S, finalInstruction), Instruction.Create(OpCodes.Ldnull), Instruction.Create(OpCodes.Ldftn, handlerConstructor), Instruction.Create(OpCodes.Newobj, genericConstructor), Instruction.Create(OpCodes.Stsfld, handlerField), Instruction.Create(OpCodes.Br_S, finalInstruction), finalInstruction }); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldnull)); } var registerPropertyInvoker = (propertyData.DefaultValue == null) ? _catelType.RegisterPropertyWithoutDefaultValueInvoker : _catelType.RegisterPropertyWithDefaultValueInvoker; var parameters = registerPropertyInvoker.Parameters.Reverse().ToList(); for (int i = 0; i < parameters.Count; i++) { var parameterType = parameters[i]; if (string.CompareOrdinal(parameterType.ParameterType.FullName, FodyEnvironment.ModuleDefinition.TypeSystem.Boolean.FullName) != 0) { break; } instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4_1)); } // Make call to register property generic var finalRegisterPropertyMethod = registerPropertyInvoker; if (registerPropertyInvoker.HasGenericParameters) { var genericRegisterProperty = new GenericInstanceMethod(registerPropertyInvoker); if (registerPropertyInvoker.HasGenericParameters) { foreach (var genericParameter in registerPropertyInvoker.GenericParameters) { genericRegisterProperty.GenericParameters.Add(genericParameter); } genericRegisterProperty.GenericArguments.Add(property.PropertyType.Import(true)); } finalRegisterPropertyMethod = genericRegisterProperty; } instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Call, finalRegisterPropertyMethod), Instruction.Create(OpCodes.Stsfld, fieldReference) }); instructions.Insert(index, instructionsToInsert); body.OptimizeMacros(); return(true); }
private bool AddPropertyRegistration(PropertyDefinition property, CatelTypeProperty propertyData) { var fieldName = $"{property.Name}Property"; var declaringType = property.DeclaringType; var fieldReference = GetFieldReference(declaringType, fieldName, true); if (fieldReference == null) { FodyEnvironment.LogWarning($"\t\tCannot handle property '{_catelType.Name}.{property.Name}' because backing field is not found"); return false; } var staticConstructor = declaringType.Constructor(true); var body = staticConstructor.Body; body.SimplifyMacros(); var instructions = body.Instructions; // Always inject before the first try block, or just before the last return statement var instructionToInsert = (from instruction in instructions where instruction.OpCode == OpCodes.Ret select instruction).FirstOrDefault(); var exceptionHandler = body.ExceptionHandlers.FirstOrDefault(); if (exceptionHandler != null) { instructionToInsert = exceptionHandler.TryStart; } var index = (instructionToInsert != null) ? instructions.IndexOf(instructionToInsert) : instructions.Count; //L_0000: ldstr "FullName" //L_0005: ldtoken string // note that this is the property type //L_000a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) //L_000f: ldnull //L_0010: ldnull //L_0011: ldc.i4.1 //L_0012: call class [Catel.Core]Catel.Data.PropertyData [Catel.Core]Catel.Data.ModelBase::RegisterProperty(string, class [mscorlib]System.Type, class [mscorlib]System.Func`1<object>, class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs>, bool) //L_0017: stsfld class [Catel.Core]Catel.Data.PropertyData Catel.Fody.TestAssembly.ViewModelBaseTest::FullNameProperty var getTypeFromHandle = property.Module.GetMethodAndImport("GetTypeFromHandle"); var instructionsToInsert = new List<Instruction>(); instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Ldstr, property.Name), Instruction.Create(OpCodes.Ldtoken, property.PropertyType.Import()), Instruction.Create(OpCodes.Call, getTypeFromHandle), }); var resolvedPropertyType = propertyData.PropertyDefinition.PropertyType.Resolve(); // Default value if (propertyData.DefaultValue is string) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldstr, (string)propertyData.DefaultValue)); } else if (propertyData.DefaultValue is bool) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (bool)propertyData.DefaultValue ? 1 : 0)); } else if (propertyData.DefaultValue is int) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (int)propertyData.DefaultValue)); } else if (propertyData.DefaultValue is long) { if ((long)propertyData.DefaultValue <= int.MaxValue) { // Note: don't use Ldc_I8 here, although it is a long instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (int)(long)propertyData.DefaultValue)); instructionsToInsert.Add(Instruction.Create(OpCodes.Conv_I8)); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I8, (long)propertyData.DefaultValue)); } } else if (propertyData.DefaultValue is float) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_R4, (float)propertyData.DefaultValue)); } else if (propertyData.DefaultValue is double) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_R8, (double)propertyData.DefaultValue)); } else if (resolvedPropertyType != null && resolvedPropertyType.IsEnum && propertyData.DefaultValue != null) { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4, (int)((CustomAttributeArgument)propertyData.DefaultValue).Value)); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldnull)); } if (propertyData.ChangeCallbackReference != null) { //L_0040: ldsfld class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> Catel.Fody.TestAssembly.ModelBaseTest::CS$<>9__CachedAnonymousMethodDelegate1 //L_0045: brtrue.s L_005a //L_0047: ldnull //L_0048: ldftn void Catel.Fody.TestAssembly.ModelBaseTest::<.cctor>b__0(object, class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs) //L_004e: newobj instance void [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs>::.ctor(object, native int) //L_0053: stsfld class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> Catel.Fody.TestAssembly.ModelBaseTest::CS$<>9__CachedAnonymousMethodDelegate1 //L_0058: br.s L_005a //L_005a: ldsfld class [mscorlib]System.EventHandler`1<class [Catel.Core]Catel.Data.AdvancedPropertyChangedEventArgs> Catel.Fody.TestAssembly.ModelBaseTest::CS$<>9__CachedAnonymousMethodDelegate1 string handlerFieldName = GetChangeNotificationHandlerFieldName(property); string handlerConstructorFieldName = GetChangeNotificationHandlerConstructorName(property); var handlerField = GetFieldReference(property.DeclaringType, handlerFieldName, true); var handlerConstructor = GetMethodReference(property.DeclaringType, handlerConstructorFieldName, true); var handlerType = GetEventHandlerAdvancedPropertyChangedEventArgs(property); var importedHandlerType = handlerType.Resolve(); var advancedPropertyChangedEventArgsType = property.Module.FindType("Catel.Core", "Catel.Data.AdvancedPropertyChangedEventArgs"); var handlerTypeConstructor = declaringType.Module.Import(importedHandlerType.Constructor(false)); var genericConstructor = handlerTypeConstructor.MakeHostInstanceGeneric(declaringType.Module.Import(advancedPropertyChangedEventArgsType)); var finalInstruction = Instruction.Create(OpCodes.Ldsfld, handlerField); instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Ldsfld, handlerField), Instruction.Create(OpCodes.Brtrue_S, finalInstruction), Instruction.Create(OpCodes.Ldnull), Instruction.Create(OpCodes.Ldftn, handlerConstructor), Instruction.Create(OpCodes.Newobj, genericConstructor), Instruction.Create(OpCodes.Stsfld, handlerField), Instruction.Create(OpCodes.Br_S, finalInstruction), finalInstruction }); } else { instructionsToInsert.Add(Instruction.Create(OpCodes.Ldnull)); } var registerPropertyInvoker = (propertyData.DefaultValue == null) ? _catelType.RegisterPropertyWithoutDefaultValueInvoker : _catelType.RegisterPropertyWithDefaultValueInvoker; var parameters = registerPropertyInvoker.Parameters.Reverse().ToList(); for (int i = 0; i < parameters.Count; i++) { var parameterType = parameters[i]; if (string.CompareOrdinal(parameterType.ParameterType.FullName, FodyEnvironment.ModuleDefinition.TypeSystem.Boolean.FullName) != 0) { break; } instructionsToInsert.Add(Instruction.Create(OpCodes.Ldc_I4_1)); } // Make call to register property generic var finalRegisterPropertyMethod = registerPropertyInvoker; if (registerPropertyInvoker.HasGenericParameters) { var genericRegisterProperty = new GenericInstanceMethod(registerPropertyInvoker); if (registerPropertyInvoker.HasGenericParameters) { foreach (var genericParameter in registerPropertyInvoker.GenericParameters) { genericRegisterProperty.GenericParameters.Add(genericParameter); } genericRegisterProperty.GenericArguments.Add(property.PropertyType.Import(true)); } finalRegisterPropertyMethod = genericRegisterProperty; } instructionsToInsert.AddRange(new[] { Instruction.Create(OpCodes.Call, finalRegisterPropertyMethod), Instruction.Create(OpCodes.Stsfld, fieldReference) }); instructions.Insert(index, instructionsToInsert); body.OptimizeMacros(); return true; }
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); }