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));
            }