XmlSerializable and System.Drawing.Color
יצא לי לכתוב מחלקה שנראית כך:
public struct EnviormentColor
{
public string Name { get; set; }
public Color ForeColor { get; set; }
public Color BackColor { get; set; }
}
כפי שאפשר לראות המבנה מכיל שם ושני צבעים (צבע רקע וצבע פונט).
כעת היה לי מערך של המבנה הזה, ניסיתי להפעיל עליו את מנגנון
הסיראליזציה של xml, בצורה הבאה:
XmlSerializer serializer = new XmlSerializer(typeof(List<EnviormentColor>));
serializer.Serialize(File.OpenWrite("colors.xml"), list);
כעת קרה דבר מעניין, כך נראתה התוצאה:
<?xml version="1.0"?>
<ArrayOfEnviormentColor>
<EnviormentColor>
<Name>Shlomo</Name>
<ForeColor />
<BackColor />
</EnviormentColor>
<EnviormentColor>
<Name>Noam</Name>
<ForeColor />
<BackColor />
</EnviormentColor>
<EnviormentColor>
<Name>Yossi</Name>
<ForeColor />
<BackColor />
</EnviormentColor>
<EnviormentColor>
<Name>david</Name>
<ForeColor />
<BackColor />
</EnviormentColor>
</ArrayOfEnviormentColor>
כפי שאפשר לראות רק השמות נכתבו בקובץ אך לא הערכים של הצבעים.
לאחר קצת שיטוטים בגוגל, הבנתי שמנגנון הסירלזיציה של xml עושה זאת רק עבור מאפיינים שיש להם get;set; ולמאפיין Name של Color אין set.
ישנם כמה דרכים מוזרות לתקן זאת, אני בחרתי בצורה שנראתה לי הכי הגיונית, מימוש של IXmlSerializable, הממשק הזה מאפשר לנו להחליט כיצד יתבצע שיטוח של האובייקטים שלנו.
ולכן נשנה את הקוד שלנו קצת.
public struct EnviormentColor : IXmlSerializable
{
public string Name { get; set; }
public Color ForeColor { get; set; }
public Color BackColor { get; set; }
#region IXmlSerializable
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
Name = reader.ReadElementString();
BackColor = Color.FromName(reader.ReadElementString());
ForeColor = Color.FromName(reader.ReadElementString());
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("Name", Name);
writer.WriteElementString("BackColor", BackColor.Name);
writer.WriteElementString("ForeColor", ForeColor.Name);
}
#endregion
}
כעת ההרצה של הקוד המבצע שיטוח של האובייקט ייתן את התוצר הבא:
<?xml version="1.0"?>
<ArrayOfEnviormentColor>
<EnviormentColor>
<Name>Shlomo</Name>
<BackColor>Red</BackColor>
<ForeColor>#aa33ff</ForeColor>
</EnviormentColor>
<EnviormentColor>
<Name>Noam</Name>
<BackColor>Red</BackColor>
<ForeColor>#331100</ForeColor>
</EnviormentColor>
<EnviormentColor>
<Name>Yossi</Name>
<BackColor>Green</BackColor>
<ForeColor>Blue</ForeColor>
</EnviormentColor>
</ArrayOfEnviormentColor>
חשוב לשים לב לשורת ה - reader.ReadEndElement בפונקציית ReadXml, בלי שנקדם בכל פעם את ה - reader לסוף האלמנט הנוכחי, מנגנון הסירליזצייה יחשוב שהגענו לסוף הקובץ ויחזיר רק אלמנט אחד במערך.