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); switch (Type.GetTypeCode(propertyType)) { case TypeCode.Boolean: this.Writer.WriteAttributeString("attr.type", "boolean"); break; case TypeCode.Int32: this.Writer.WriteAttributeString("attr.type", "int"); break; case TypeCode.Int64: this.Writer.WriteAttributeString("attr.type", "long"); break; case TypeCode.Single: this.Writer.WriteAttributeString("attr.type", "float"); break; case TypeCode.Double: this.Writer.WriteAttributeString("attr.type", "double"); break; case TypeCode.String: this.Writer.WriteAttributeString("attr.type", "string"); break; default: throw new NotSupportedException(String.Format("Property type {0}.{1} not supported by the GraphML schema", property.DeclaringType, property.Name)); } // <default>...</default> object defaultValue; if (kv.TryGetDefaultValue(out defaultValue)) { this.Writer.WriteStartElement("default"); switch (Type.GetTypeCode(defaultValue.GetType())) { 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; 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); gen.EmitCall(OpCodes.Callvirt, 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)); }