Catel.Fody.CatelPropertyWeaver.AddPropertyRegistration C# (CSharp) Метод

AddPropertyRegistration() приватный Метод

private AddPropertyRegistration ( Mono.Cecil.PropertyDefinition property, CatelTypeProperty propertyData ) : bool
property Mono.Cecil.PropertyDefinition
propertyData CatelTypeProperty
Результат bool
        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;
        }