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); }
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); }
/// <summary> /// Implements the .GetTypes method which returns a list of all annotated RDF classes for a given type. /// </summary> /// <param name="parameter">A type defintion.</param> /// <returns><c>true</c> on success, <c>false</c> otherwise.</returns> public override bool Execute(object parameter = null) { List <string> uris = new List <string>(); // Accumulate the annotated RDF classes. foreach (CustomAttribute attribute in Type.TryGetCustomAttribute("RdfClassAttribute")) { uris.Insert(0, attribute.ConstructorArguments.First().Value.ToString()); } if (uris.Count == 0) { if (!Type.Methods.Any(m => m.Name == "GetTypes")) { string msg = "{0}: Mapped type has no annotated RDF classes and no overridden GetTypes() method."; throw new Exception(string.Format(msg, Type.FullName)); } return(false); } TypeDefinition[] types = { Type }; MethodDefinition getTypes = null; MethodReference getTypeBase = null; // We iterate through the type hierarchy from top to bottom and find the first GetTypes // method. That one serves as a template for the override method of the current type in // which the instructions are being replaced. foreach (TypeDefinition t in types.Union(Type.GetBaseTypes()).Reverse()) { getTypes = t.TryGetInheritedMethod("GetTypes"); if (getTypes != null && getTypeBase == null) { getTypeBase = getTypes; break; } } if (getTypes == null) { throw new ArgumentException("{0}: Found no GetTypes() method for type.", Type.FullName); } if (getTypeBase == null) { throw new ArgumentException(string.Format("{0}: Failed to find virtual base method of {1}", Type.FullName, getTypes.FullName)); } // The override method must be created in the module where the type is defined. getTypes = getTypeBase.GetOverrideMethod(MainModule); MethodGeneratorTask generator = new MethodGeneratorTask(getTypes); generator.Instructions.AddRange(GenerateGetTypesInstructions(generator.Processor, uris)); if (generator.CanExecute()) { generator.Method.Body.MaxStackSize = 3; generator.Method.Body.InitLocals = true; generator.Method.Body.Variables.Add(new VariableDefinition(MainModule.ImportReference(getTypeBase.ReturnType))); generator.Method.Body.Variables.Add(new VariableDefinition(ClassArrayType)); generator.Execute(); MainModule.ImportReference(ClassType); } Type.Methods.Add(getTypes); foreach (string uri in uris) { Log.LogMessage("{0} -> <{1}>", Type.FullName, uri); } return(true); }
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); }