Example #1
0
        internal FieldDefinition ImplementMappingField(PropertyDefinition property)
        {
            // Load the property mapping type.
            TypeReference mappingType = MainModule.Import(typeof(PropertyMapping <>));

            Assert.IsNotNull(mappingType, "{0}: Failed to import type {1}.", Assembly.FullName, mappingType.FullName);

            // Add the property type as generic parameter.
            GenericInstanceType fieldType = new GenericInstanceType(mappingType);

            fieldType.GenericArguments.Add(property.PropertyType);

            // Generate the name of the private backing field.
            string fieldName = "_" + Char.ToLowerInvariant(property.Name[0]) + property.Name.Substring(1) + "Mapping";

            // Implement the field.
            FieldDefinition mappingField = new FieldDefinition(fieldName, FieldAttributes.Family, fieldType);

            Type.Fields.Add(mappingField);

            FieldReference backingField = property.TryGetBackingField();

            if (backingField != null)
            {
                Type.Fields.Remove(backingField.Resolve());
            }

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            if (!Uri.IsWellFormedUriString(p.Uri, UriKind.Absolute))
            {
                throw new UriFormatException("Annotated URI must be in absolute format.");
            }

            // Finally, implement the field initializers in the constructors of the class.
            foreach (MethodDefinition ctor in Type.GetConstructors())
            {
                // Implementing mapping fields in static constructors results in invalid byte code,
                // since there is no ldarg.0 (this) variable.
                if (ctor.IsStatic)
                {
                    continue;
                }

                MethodGeneratorTask g = new MethodGeneratorTask(ctor);
                g.Instructions.AddRange(GetFieldInitializationInstructions(g.Processor, p, fieldType));
                g.Instructions.AddRange(ctor.Body.Instructions);

                if (g.CanExecute())
                {
                    g.Execute();
                }
            }

            return(mappingField);
        }
Example #2
0
        private bool ImplementPropertyMapping(PropertyDefinition property, MethodDefinition raisePropertyChanged)
        {
            ImplementRdfPropertyTask subtask = new ImplementRdfPropertyTask(Generator, Type);

            FieldDefinition mappingField = subtask.ImplementMappingField(property);

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            MethodGeneratorTask getValueGenerator = subtask.GetGetValueGenerator(p);
            MethodGeneratorTask setValueGenerator = subtask.GetSetValueGenerator(p);

            if (!getValueGenerator.CanExecute())
            {
                string msg = "{0}.{1}: Failed to implement property getter.";
                throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
            }

            if (!setValueGenerator.CanExecute())
            {
                string msg = "{0}.{1}: Failed to implement property setter.";
                throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
            }

            Instruction ret = setValueGenerator.Processor.Create(OpCodes.Ret);

            // Instructions for calling SetValue()
            IList <Instruction> sv = new List <Instruction>(setValueGenerator.Instructions);

            sv.RemoveAt(0);            // Remove the first nop-Instruction..
            sv.RemoveAt(sv.Count - 1); // Remove the ret-Instruction..

            // Instructions for return on equal values.
            MethodReference getValue = Type.TryGetGetValueMethod(Assembly, property.PropertyType);

            IList <Instruction> roe = GetReturnOnEqualsInstructionsForMapping(setValueGenerator.Processor, mappingField, getValue, sv.First(), ret).ToList();

            Assert.Greater(roe.Count, 0, "{0}.{1}: Failed to generate byte code for return on equality.", Type.FullName, property.Name);

            // Instructions for calling RaisePropertyChanged()
            IList <Instruction> rpc = GetRaisePropertyChangedInstructions(setValueGenerator.Processor, property, raisePropertyChanged).ToList();

            Assert.Greater(rpc.Count, 0, "{0}: Failed to generate byte code for calling the RaisePropertyChanged() method.", Type.FullName);

            // Re-write the instructions for the SetValue() method generator.
            setValueGenerator.Processor.Body.MaxStackSize = IsMappedProperty ? 4 : 2;
            setValueGenerator.Instructions.Clear();
            setValueGenerator.Instructions.AddRange(roe);
            setValueGenerator.Instructions.AddRange(sv);
            setValueGenerator.Instructions.AddRange(rpc);
            setValueGenerator.Instructions.Add(ret);
            setValueGenerator.Execute();

            getValueGenerator.Execute();

            return(true);
        }
        public override bool Execute(object parameter = null)
        {
            PropertyDefinition property = parameter as PropertyDefinition;

            if (property == null)
            {
                return(false);
            }

            FieldDefinition mappingField = ImplementMappingField(property);

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            if (p.Property.GetMethod != null)
            {
                if (p.Property.GetMethod.HasCustomAttribute <CompilerGeneratedAttribute>() || p.Property.GetMethod.IsCompilerControlled)
                {
                    MethodGeneratorTask getValueGenerator = GetGetValueGenerator(p);

                    if (getValueGenerator.CanExecute())
                    {
                        getValueGenerator.Execute();
                    }
                    else
                    {
                        string msg = "{0}.{1}: Failed to implement property getter.";
                        throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
                    }
                }
            }

            if (p.Property.SetMethod != null)
            {
                if (p.Property.SetMethod.HasCustomAttribute <CompilerGeneratedAttribute>() || p.Property.SetMethod.IsCompilerControlled)
                {
                    MethodGeneratorTask setValueGenerator = GetSetValueGenerator(p);

                    if (setValueGenerator.CanExecute())
                    {
                        setValueGenerator.Execute();
                    }
                    else
                    {
                        string msg = "{0}.{1}: Failed to implement property setter.";
                        throw new Exception(string.Format(msg, property.DeclaringType.FullName, property.Name));
                    }
                }
            }

            Log.LogMessage("{0}.{1} -> <{2}>", Type.FullName, property.Name, p.Uri);

            return(true);
        }
Example #4
0
        internal MethodGeneratorTask GetSetValueGenerator(PropertyGeneratorTaskHelper p)
        {
            // Load a reference to the SetValue method for the property mapping.
            MethodReference setValue = Type.TryGetSetValueMethod(Assembly, p.Property.PropertyType);

            Assert.IsNotNull(setValue, "{0}: Type has no SetValue() method.", p.Property.DeclaringType.FullName);

            MethodGeneratorTask generator = new MethodGeneratorTask(p.Property.SetMethod);

            generator.Instructions.AddRange(GetCallSetValueInstructions(generator.Processor, p, setValue));

            return(generator);
        }
        internal MethodGeneratorTask GetGetValueGenerator(PropertyGeneratorTaskHelper p)
        {
            // Load a reference to the GetValue method for the property mapping.
            MethodReference getValue = Type.TryGetGetValueMethod(Assembly, p.Property.PropertyType);

            if (getValue == null)
            {
                throw new ArgumentException("{0}: Type has no GetValue() method.", p.Property.DeclaringType.FullName);
            }

            MethodGeneratorTask generator = new MethodGeneratorTask(p.Property.GetMethod);

            generator.Instructions.AddRange(GetReturnGetValueInstructions(generator.Processor, p, getValue));

            return(generator);
        }
        private IEnumerable <Instruction> GetFieldInitializationInstructions(ILProcessor processor, PropertyGeneratorTaskHelper p, TypeReference mappingType)
        {
            MethodDefinition ctorDef;

            if (p.HasDefaultValue)
            {
                ctorDef = GetPropertyMappingConstructorDefinition(mappingType, p.DefaultValue);
            }
            else
            {
                ctorDef = GetPropertyMappingConstructorDefinition(mappingType);
            }

            if (ctorDef == null)
            {
                yield break;
            }

            MethodReference ctor = Generator.Assembly.MainModule.ImportReference(ctorDef);

            // Thanks to: http://stackoverflow.com/questions/4968755/mono-cecil-call-generic-base-class-method-from-other-assembly
            if (mappingType.IsGenericInstance)
            {
                var genericType = mappingType as GenericInstanceType;

                ctor = MakeGeneric(ctor, genericType.GenericArguments.ToArray());
            }

            yield return(processor.Create(OpCodes.Ldarg_0));

            yield return(processor.Create(OpCodes.Ldstr, p.Property.Name));

            yield return(processor.Create(OpCodes.Ldstr, p.Uri));

            if (p.HasDefaultValue)
            {
                if (p.Initializer == null)
                {
                    foreach (Instruction i in GetLdX(processor, p.DefaultValue))
                    {
                        yield return(i);
                    }
                }
                else
                {
                    foreach (var inst in p.Initializer)
                    {
                        yield return(inst);
                    }
                }
            }

            if (p.LanguageInvariant)
            {
                yield return(processor.Create(OpCodes.Ldc_I4_1));
            }
            else
            {
                yield return(processor.Create(OpCodes.Ldc_I4_0));
            }

            yield return(processor.Create(OpCodes.Newobj, ctor));

            yield return(processor.Create(OpCodes.Stfld, p.BackingField));
        }
        private IEnumerable <Instruction> GetReturnGetValueInstructions(ILProcessor processor, PropertyGeneratorTaskHelper p, MethodReference getValue)
        {
            processor.Create(OpCodes.Ldloc_0);

            foreach (Instruction i in GetCallGetValueInstructions(processor, p, getValue))
            {
                yield return(i);
            }

            yield return(processor.Create(OpCodes.Ret));
        }
        private IEnumerable <Instruction> GetCallGetValueInstructions(ILProcessor processor, PropertyGeneratorTaskHelper p, MethodReference getValue)
        {
            yield return(processor.Create(OpCodes.Nop));

            yield return(processor.Create(OpCodes.Ldarg_0));

            yield return(processor.Create(OpCodes.Ldarg_0));

            yield return(processor.Create(OpCodes.Ldfld, p.BackingField));

            yield return(processor.Create(OpCodes.Callvirt, getValue));
        }
        internal FieldDefinition ImplementMappingField(PropertyDefinition property)
        {
            // Load the property mapping type.
            TypeReference mappingType = MainModule.ImportReference(ILGenerator.PropertyMapping);

            if (mappingType == null)
            {
                throw new ArgumentException(string.Format("{0}: Failed to import type {1}.", Assembly.FullName, mappingType.FullName));
            }

            // Add the property type as generic parameter.
            GenericInstanceType fieldType = new GenericInstanceType(mappingType);

            fieldType.GenericArguments.Add(property.PropertyType);

            // Generate the name of the private backing field.
            string fieldName = "<" + Char.ToLowerInvariant(property.Name[0]) + property.Name.Substring(1) + ">" + "k__" + "MappingField";

            var mappingField = Type.TryGetField(fieldName);

            if (mappingField == null)
            {
                // Implement the field.
                mappingField = new FieldDefinition(fieldName, FieldAttributes.Family, fieldType);
                Type.Fields.Add(mappingField);
            }

            FieldReference backingField = property.TryGetBackingField();

            if (backingField != null)
            {
                Type.Fields.Remove(backingField.Resolve());
            }

            PropertyGeneratorTaskHelper p = new PropertyGeneratorTaskHelper(property, mappingField);

            if (!Uri.IsWellFormedUriString(p.Uri, UriKind.Absolute))
            {
                throw new UriFormatException("Annotated URI must be in absolute format.");
            }

            // Finally, implement the field initializers in the constructors of the class.
            foreach (MethodDefinition ctor in Type.GetConstructors())
            {
                // Implementing mapping fields in static constructors results in invalid byte code,
                // since there is no ldarg.0 (this) variable.
                if (ctor.IsStatic)
                {
                    continue;
                }

                MethodGeneratorTask g = new MethodGeneratorTask(ctor);

                List <Instruction> Omit = new List <Instruction>();
                bool alreadyInitialized = false;
                foreach (var x in ctor.Body.Instructions)
                {
                    if (backingField != null && x.Operand == backingField)
                    {
                        p.Initializer = new List <Instruction>();
                        Omit.Add(x);
                        var inst = x;
                        while (inst.Previous.OpCode.Code != Code.Ldarg_0)
                        {
                            inst = inst.Previous;
                            p.Initializer.Insert(0, inst);
                            // Remove this initializiation from constructor
                            Omit.Add(inst);
                        }
                        Omit.Add(inst.Previous);
                    }
                    if (mappingField != null && x.Operand != null && x.Operand is FieldDefinition && (x.Operand as FieldDefinition).FullName == mappingField.FullName)
                    {
                        alreadyInitialized = true;
                        continue;
                    }
                }
                if (alreadyInitialized)
                {
                    continue;
                }

                g.Instructions.AddRange(GetFieldInitializationInstructions(g.Processor, p, fieldType));
                g.Instructions.AddRange(ctor.Body.Instructions.Where((x) => !Omit.Contains(x)));

                if (g.CanExecute())
                {
                    g.Execute();
                }
            }


            return(mappingField);
        }