我正在尝试序列化一个继承自实现IXmlSerializable的基类的类.
名为PropertyBag的基类是一个允许动态属性的类(credits to Marc Gravell).
我实现了IXmlSerializable,以便动态属性(存储在Dictionary中)被写为普通的xml元素.
例如
当序列化具有公共属性(非动态)名称和动态属性Age的类时,我希望它生成以下XML:
<Person> <Name>Tim</Name> <DynamicProperties> <Country> <string>USA</string> </Country> </DynamicProperties> <Person>
我可以让这个部分在基础PropertyBag类中使用WriteXml的以下实现:
public void WriteXml(System.Xml.XmlWriter writer) { writer.WriteStartElement("DynamicProperties"); // serialize every dynamic property and add it to the parent writer foreach (KeyValuePair<string,object> kvp in properties) { writer.WriteStartElement(kvp.Key); StringBuilder itemXml = new StringBuilder(); using (XmlWriter itemWriter = XmlWriter.Create(itemXml)) { // serialize the item XmlSerializer xmlSer = new XmlSerializer(kvp.Value.GetType()); xmlSer.Serialize(itemWriter,kvp.Value); // read in the serialized xml XmlDocument doc = new XmlDocument(); doc.LoadXml(itemXml.ToString()); // write to modified content to the parent writer writer.WriteRaw(doc.DocumentElement.OuterXml); } writer.WriteEndElement(); } writer.WriteEndElement(); }
但是,在序列化Person类时,它不再序列化正常(非动态)属性,除非我在Person中覆盖WriteXml方法(我不想这样做).有没有办法在基类中我可以自动添加静态属性?我知道我可以使用反射手动执行此操作,但我想知道.Net Framework中是否有一些内置功能?
解决方法
我花了很多时间使用XmlSerializer(以及其他各种序列化API),我很确定这一点:你做不到.实现IXmlSerializable是全有或全无.
我能想到的最接近的是欺骗并将所有固定属性移动到子对象;这会给你略微不同的xml – 类似于:
<FixedProperties> <Name>Tim</Name> </FixedProperties> <DynamicProperties> <Country> <string>USA</string> </Country> </DynamicProperties>
但我希望它能奏效.您将在基础对象上具有pass-thru属性:
[Browsable(false),EditorBrowsable(EditorBrowsableState.Never)] public FixedProperties FixedProps {get;set;} public string Name { get {return FixedProps.Name;} set {FixedProps.Name = value;} }
合理?你也可以将Name标记为[XmlIgnore],但它看起来很冗余.在您的定制序列化方法中,您将使用新的XmlSerializer(typeof(FixedProperties))
编辑:这是一个有效的“序列化”示例:
using System; using System.ComponentModel; using System.Xml.Serialization; static class Program { static void Main() { MyType obj = new MyType { Name = "Fred" }; var ser = new XmlSerializer(obj.GetType()); ser.Serialize(Console.Out,obj); } } public class MyType : IXmlSerializable { public MyType() { FixedProperties = new MyTypeFixedProperties(); } [Browsable(false),EditorBrowsable(EditorBrowsableState.Never)] public MyTypeFixedProperties FixedProperties { get; set; } [XmlIgnore] public string Name { get { return FixedProperties.Name; } set { FixedProperties.Name = value; } } System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { return null; } void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { throw new System.NotImplementedException(); } void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { writer.WriteStartElement("DynamicProperties"); writer.WriteElementString("Foo","Bar"); writer.WriteEndElement(); fixedPropsSerializer.Serialize(writer,FixedProperties); } static readonly XmlSerializer fixedPropsSerializer = new XmlSerializer(typeof(MyTypeFixedProperties)); } [XmlRoot("FixedProperties")] public class MyTypeFixedProperties { public string Name { get; set; } }