예제 #1
0
        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;
        }
예제 #2
0
        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);
        }
예제 #3
0
        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;
        }
예제 #4
0
        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;
        }
예제 #5
0
        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);
        }