private void WriteAttributeDefinitions(string forNode, Type nodeType) { foreach (KeyValuePair <PropertyInfo, string> kv in SerializationHelper.GetAttributeProperties(nodeType)) { //<key id="d1" for="edge" attr.name="weight" attr.type="double"/> this.Writer.WriteStartElement("key"); this.Writer.WriteAttributeString("id", kv.Value); this.Writer.WriteAttributeString("for", forNode); this.Writer.WriteAttributeString("attr.name", kv.Value); Type propertyType = kv.Key.PropertyType; if (propertyType == typeof(bool)) { this.Writer.WriteAttributeString("attr.type", "boolean"); } else if (propertyType == typeof(int)) { this.Writer.WriteAttributeString("attr.type", "int"); } else if (propertyType == typeof(long)) { this.Writer.WriteAttributeString("attr.type", "long"); } else if (propertyType == typeof(float)) { this.Writer.WriteAttributeString("attr.type", "float"); } else if (propertyType == typeof(double)) { this.Writer.WriteAttributeString("attr.type", "double"); } else { this.Writer.WriteAttributeString("attr.type", "string"); } this.Writer.WriteEndElement(); } }
public static Delegate CreateReadDelegate( Type delegateType, Type elementType //,params string[] ignoredAttributes ) { Contract.Requires(delegateType != null); Contract.Requires(elementType != null); var method = new DynamicMethod( "Read" + elementType.Name, typeof(void), // reader, namespaceUri new Type[] { typeof(XmlReader), typeof(string), elementType }, elementType.Module ); var gen = method.GetILGenerator(); var key = gen.DeclareLocal(typeof(string)); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "key"); gen.EmitCall(OpCodes.Callvirt, Metadata.GetAttributeMethod, null); gen.Emit(OpCodes.Stloc_0); //// if (String.Equals(key, "id")) continue; //foreach (string ignoredAttribute in ignoredAttributes) //{ // gen.Emit(OpCodes.Ldloc_0); // gen.Emit(OpCodes.Ldstr, ignoredAttribute); // gen.EmitCall(OpCodes.Call, Metadata.StringEqualsMethod, null); // gen.Emit(OpCodes.Brtrue, doWhile); //} // we need to create the swicth for each property var next = gen.DefineLabel(); var @return = gen.DefineLabel(); bool first = true; foreach (var kv in SerializationHelper.GetAttributeProperties(elementType)) { var property = kv.Property; if (!first) { gen.MarkLabel(next); next = gen.DefineLabel(); } first = false; // if (!key.Equals("foo")) gen.Emit(OpCodes.Ldloc_0); gen.Emit(OpCodes.Ldstr, kv.Name); gen.EmitCall(OpCodes.Call, Metadata.StringEqualsMethod, null); // if false jump to next gen.Emit(OpCodes.Brfalse, next); // do our stuff MethodInfo readMethod = null; if (!Metadata.TryGetReadContentMethod(property.PropertyType, out readMethod)) { throw new ArgumentException(String.Format("Property {0} has a non-supported type", property.Name)); } // do we have a set method ? var setMethod = property.GetSetMethod(); if (setMethod == null) { throw new ArgumentException(String.Format("Property {0}.{1} has not set method", property.DeclaringType, property.Name)); } // reader.ReadXXX gen.Emit(OpCodes.Ldarg_2); // element gen.Emit(OpCodes.Ldarg_0); // reader gen.Emit(OpCodes.Ldstr, "data"); gen.Emit(OpCodes.Ldarg_1); // namespace uri gen.EmitCall(OpCodes.Callvirt, readMethod, null); gen.EmitCall(OpCodes.Callvirt, setMethod, null); // jump to do while gen.Emit(OpCodes.Br, @return); } // we don't know this parameter.. we throw gen.MarkLabel(next); gen.Emit(OpCodes.Ldloc_0); gen.Emit(OpCodes.Newobj, Metadata.ArgumentExceptionCtor); gen.Emit(OpCodes.Throw); gen.MarkLabel(@return); gen.Emit(OpCodes.Ret); //let's bake the method return(method.CreateDelegate(delegateType)); }
public static Delegate CreateSetDefaultDelegate( Type delegateType, Type elementType ) { Contract.Requires(delegateType != null); Contract.Requires(elementType != null); var method = new DynamicMethod( "Set" + elementType.Name + "Default", typeof(void), new Type[] { elementType }, elementType.Module ); var gen = method.GetILGenerator(); // we need to create the swicth for each property foreach (var kv in SerializationHelper.GetAttributeProperties(elementType)) { var property = kv.Property; var defaultValueAttribute = Attribute.GetCustomAttribute(property, typeof(DefaultValueAttribute)) as DefaultValueAttribute; if (defaultValueAttribute == null) { continue; } var setMethod = property.GetSetMethod(); if (setMethod == null) { throw new InvalidOperationException("property " + property.Name + " is not settable"); } var value = defaultValueAttribute.Value; if (value != null && value.GetType() != property.PropertyType) { throw new InvalidOperationException("invalid default value type of property " + property.Name); } gen.Emit(OpCodes.Ldarg_0); switch (Type.GetTypeCode(property.PropertyType)) { case TypeCode.Int32: gen.Emit(OpCodes.Ldc_I4, (int)value); break; case TypeCode.Int64: gen.Emit(OpCodes.Ldc_I8, (long)value); break; case TypeCode.Single: gen.Emit(OpCodes.Ldc_R4, (float)value); break; case TypeCode.Double: gen.Emit(OpCodes.Ldc_R8, (double)value); break; case TypeCode.String: gen.Emit(OpCodes.Ldstr, (string)value); break; case TypeCode.Boolean: gen.Emit((bool)value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); break; default: throw new InvalidOperationException("unsupported type " + property.PropertyType); } gen.EmitCall(setMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, setMethod, null); } gen.Emit(OpCodes.Ret); //let's bake the method return(method.CreateDelegate(delegateType)); }
private void WriteAttributeDefinitions(string forNode, Type nodeType) { Contract.Requires(forNode != null); Contract.Requires(nodeType != null); foreach (var kv in SerializationHelper.GetAttributeProperties(nodeType)) { var property = kv.Property; var name = kv.Name; Type propertyType = property.PropertyType; { //<key id="d1" for="edge" attr.name="weight" attr.type="double"/> this.Writer.WriteStartElement("key", GraphMLXmlResolver.GraphMLNamespace); this.Writer.WriteAttributeString("id", name); this.Writer.WriteAttributeString("for", forNode); this.Writer.WriteAttributeString("attr.name", name); string typeCodeStr; try { typeCodeStr = ConstructTypeCode(propertyType); } catch (NotSupportedException) { throw new NotSupportedException(String.Format("Property type {0}.{1} not supported by the GraphML schema", property.DeclaringType, property.Name)); } this.Writer.WriteAttributeString("attr.type", typeCodeStr); } // <default>...</default> object defaultValue; if (kv.TryGetDefaultValue(out defaultValue)) { this.Writer.WriteStartElement("default"); var defaultValueType = defaultValue.GetType(); switch (Type.GetTypeCode(defaultValueType)) { case TypeCode.Boolean: this.Writer.WriteString(XmlConvert.ToString((bool)defaultValue)); break; case TypeCode.Int32: this.Writer.WriteString(XmlConvert.ToString((int)defaultValue)); break; case TypeCode.Int64: this.Writer.WriteString(XmlConvert.ToString((long)defaultValue)); break; case TypeCode.Single: this.Writer.WriteString(XmlConvert.ToString((float)defaultValue)); break; case TypeCode.Double: this.Writer.WriteString(XmlConvert.ToString((double)defaultValue)); break; case TypeCode.String: this.Writer.WriteString((string)defaultValue); break; case TypeCode.Object: if (defaultValueType.IsArray) { throw new NotImplementedException("Default values for array types are not implemented"); } throw new NotSupportedException(String.Format("Property type {0}.{1} not supported by the GraphML schema", property.DeclaringType, property.Name)); default: throw new NotSupportedException(String.Format("Property type {0}.{1} not supported by the GraphML schema", property.DeclaringType, property.Name)); } this.Writer.WriteEndElement(); } this.Writer.WriteEndElement(); } }
public static Delegate CreateWriteDelegate(Type nodeType, Type delegateType) { Contract.Requires(nodeType != null); Contract.Requires(delegateType != null); var method = new DynamicMethod( "Write" + delegateType.Name + nodeType.Name, typeof(void), new Type[] { typeof(XmlWriter), nodeType }, nodeType.Module ); var gen = method.GetILGenerator(); Label @default = default(Label); foreach (var kv in SerializationHelper.GetAttributeProperties(nodeType)) { var property = kv.Property; var name = kv.Name; var getMethod = property.GetGetMethod(); if (getMethod == null) { throw new NotSupportedException(String.Format("Property {0}.{1} has not getter", property.DeclaringType, property.Name)); } MethodInfo writeValueMethod; if (!Metadata.TryGetWriteValueMethod(property.PropertyType, out writeValueMethod)) { throw new NotSupportedException(String.Format("Property {0}.{1} type is not supported", property.DeclaringType, property.Name)); } var defaultValueAttribute = Attribute.GetCustomAttribute(property, typeof(DefaultValueAttribute)) as DefaultValueAttribute; if (defaultValueAttribute != null) { @default = gen.DefineLabel(); var value = defaultValueAttribute.Value; if (value != null && value.GetType() != property.PropertyType) { throw new InvalidOperationException("inconsistent default value of property " + property.Name); } switch (Type.GetTypeCode(property.PropertyType)) { case TypeCode.Int32: gen.Emit(OpCodes.Ldc_I4, (int)value); break; case TypeCode.Int64: gen.Emit(OpCodes.Ldc_I8, (long)value); break; case TypeCode.Single: gen.Emit(OpCodes.Ldc_R4, (float)value); break; case TypeCode.Double: gen.Emit(OpCodes.Ldc_R8, (double)value); break; case TypeCode.String: gen.Emit(OpCodes.Ldstr, (string)value); break; case TypeCode.Boolean: gen.Emit((bool)value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); break; default: throw new InvalidOperationException("unsupported type " + property.PropertyType); } gen.Emit(OpCodes.Ldarg_1); gen.EmitCall(OpCodes.Callvirt, getMethod, null); gen.Emit(OpCodes.Ceq); gen.Emit(OpCodes.Brtrue, @default); } // for each property of the type, // write it to the xmlwriter (we need to take care of value types, etc...) // writer.WriteStartElement("data") gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "data"); gen.Emit(OpCodes.Ldstr, GraphMLXmlResolver.GraphMLNamespace); gen.EmitCall(OpCodes.Callvirt, Metadata.WriteStartElementMethod, null); // writer.WriteStartAttribute("key"); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "key"); gen.Emit(OpCodes.Ldstr, name); gen.EmitCall(OpCodes.Callvirt, Metadata.WriteAttributeStringMethod, null); // writer.WriteValue(v.xxx); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); gen.EmitCall(OpCodes.Callvirt, getMethod, null); // When reading scalar values we call member methods of XmlReader, while for array values // we call our own static methods. These two types of methods seem to need different opcode. var opcode = writeValueMethod.DeclaringType == typeof(XmlWriterExtensions) ? OpCodes.Call : OpCodes.Callvirt; gen.EmitCall(opcode, writeValueMethod, null); // writer.WriteEndElement() gen.Emit(OpCodes.Ldarg_0); gen.EmitCall(OpCodes.Callvirt, Metadata.WriteEndElementMethod, null); if (defaultValueAttribute != null) { gen.MarkLabel(@default); @default = default(Label); } } gen.Emit(OpCodes.Ret); //let's bake the method return(method.CreateDelegate(delegateType)); }
public static Delegate CreateReadDelegate( Type delegateType, Type elementType, params string[] ignoredAttributes ) { DynamicMethod method = new DynamicMethod( "Read" + elementType.Name, typeof(void), new Type[] { typeof(XmlReader), elementType }, elementType.Module ); ILGenerator gen = method.GetILGenerator(); MethodInfo readToFollowing = typeof(XmlReader).GetMethod( "ReadToFollowing", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null); MethodInfo getAttribute = typeof(XmlReader).GetMethod( "GetAttribute", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null); MethodInfo stringEquals = typeof(string).GetMethod( "op_Equality", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { typeof(string), typeof(string) }, null); ConstructorInfo argumentException = typeof(ArgumentException).GetConstructor(new Type[] { }); // read content as methods Dictionary <Type, MethodInfo> readContentMethods = new Dictionary <Type, MethodInfo>(); readContentMethods.Add(typeof(int), typeof(XmlReader).GetMethod("ReadElementContentAsInt", new Type[] { })); readContentMethods.Add(typeof(double), typeof(XmlReader).GetMethod("ReadElementContentAsDouble", new Type[] { })); readContentMethods.Add(typeof(bool), typeof(XmlReader).GetMethod("ReadElementContentAsBoolean", new Type[] { })); readContentMethods.Add(typeof(DateTime), typeof(XmlReader).GetMethod("ReadElementContentAsDateTime", new Type[] { })); readContentMethods.Add(typeof(long), typeof(XmlReader).GetMethod("ReadElementContentAsLong", new Type[] { })); readContentMethods.Add(typeof(string), typeof(XmlReader).GetMethod("ReadElementContentAsString", new Type[] { })); LocalBuilder key = gen.DeclareLocal(typeof(string)); Label start = gen.DefineLabel(); Label doWhile = gen.DefineLabel(); gen.Emit(OpCodes.Br_S, doWhile); gen.MarkLabel(start); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "key"); gen.EmitCall(OpCodes.Callvirt, getAttribute, null); gen.Emit(OpCodes.Stloc_0); // if (key.Equals("id")) continue; foreach (string ignoredAttribute in ignoredAttributes) { gen.Emit(OpCodes.Ldloc_0); gen.Emit(OpCodes.Ldstr, ignoredAttribute); gen.EmitCall(OpCodes.Call, stringEquals, null); gen.Emit(OpCodes.Brtrue_S, doWhile); } // we need to create the swicth for each property Label next = gen.DefineLabel(); bool first = true; foreach (KeyValuePair <PropertyInfo, string> kv in SerializationHelper.GetAttributeProperties(elementType)) { if (!first) { gen.MarkLabel(next); next = gen.DefineLabel(); } first = false; // if (!key.Equals("foo")) gen.Emit(OpCodes.Ldloc_0); gen.Emit(OpCodes.Ldstr, kv.Value); gen.EmitCall(OpCodes.Callvirt, stringEquals, null); // if false jump to next gen.Emit(OpCodes.Brfalse_S, next); // do our stuff MethodInfo readMethod = null; if (!readContentMethods.TryGetValue(kv.Key.PropertyType, out readMethod)) { throw new ArgumentException(String.Format("Property {0} has a non-supported type", kv.Key.Name)); } // do we have a set method ? MethodInfo setMethod = kv.Key.GetSetMethod(); if (setMethod == null) { throw new ArgumentException( String.Format("Property {0} is readonly", kv.Key.Name) ); } // reader.ReadXXX gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Ldarg_0); gen.EmitCall(OpCodes.Callvirt, readMethod, null); gen.EmitCall(OpCodes.Callvirt, setMethod, null); // jump to do while gen.Emit(OpCodes.Br_S, doWhile); } // we don't know this parameter.. we throw gen.MarkLabel(next); gen.Emit(OpCodes.Newobj, argumentException); gen.Emit(OpCodes.Throw); gen.MarkLabel(doWhile); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "data"); gen.EmitCall(OpCodes.Callvirt, readToFollowing, null); gen.Emit(OpCodes.Brtrue_S, start); gen.Emit(OpCodes.Ret); //let's bake the method return(method.CreateDelegate(delegateType)); }
public static Delegate CreateWriteDelegate(Type nodeType, Type delegateType) { DynamicMethod method = new DynamicMethod( "Write" + delegateType.Name + nodeType.Name, typeof(void), new Type[] { typeof(XmlWriter), nodeType }, nodeType.Module ); ILGenerator gen = method.GetILGenerator(); MethodInfo writeStartElement = typeof(XmlWriter).GetMethod( "WriteStartElement", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null); MethodInfo writeEndElement = typeof(XmlWriter).GetMethod( "WriteEndElement", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null); MethodInfo writeString = typeof(XmlWriter).GetMethod( "WriteString", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null); MethodInfo writeAttributeString = typeof(XmlWriter).GetMethod( "WriteAttributeString", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string), typeof(string) }, null); MethodInfo toString = typeof(object).GetMethod( "ToString", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { }, null); foreach (KeyValuePair <PropertyInfo, string> kv in SerializationHelper.GetAttributeProperties(nodeType)) { // for each property of the type, // write it to the xmlwriter (we need to take care of value types, etc...) // writer.WriteStartElement("data") gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "data"); gen.EmitCall(OpCodes.Callvirt, writeStartElement, null); // writer.WriteAttributeString("key", name); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldstr, "key"); gen.Emit(OpCodes.Ldstr, kv.Value); gen.EmitCall(OpCodes.Callvirt, writeAttributeString, null); // writer.WriteString(v.xxx); gen.Emit(OpCodes.Ldarg_0); // we now need to load the vertex and invoke the property // load vertex gen.Emit(OpCodes.Ldarg_1); // invoke property MethodInfo getMethod = kv.Key.GetGetMethod(); gen.EmitCall( (getMethod.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, getMethod, null); // since XmlWrite takes to string, we need to convert that // object to a string... // of course, if it's a string, we don't need to do anything Type propertyType = kv.Key.PropertyType; if (propertyType != typeof(string)) { // if it's a value type, it has to be boxed before // invoking ToString if (propertyType.IsValueType) { gen.Emit(OpCodes.Box, propertyType); } gen.Emit( (toString.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, toString); } // we now have two string on the stack... gen.EmitCall(OpCodes.Callvirt, writeString, null); // writer.WriteEndElement() gen.Emit(OpCodes.Ldarg_0); gen.EmitCall(OpCodes.Callvirt, writeEndElement, null); } gen.Emit(OpCodes.Ret); //let's bake the method return(method.CreateDelegate(delegateType)); }