c#inheritancegenerics集合和序列化

设置:

class Item { private int _value; public Item() { _value = 0; } public int Value { get { return _value; } set { _value = value; } } } class ItemCollection : Collection { private string _name; public ItemCollection() { _name = string.Empty; } public string Name { get {return _name;} set {_name = value;} } } 

现在,尝试使用以下代码片段进行序列化:

 ItemCollection items = new ItemCollection(); ... XmlSerializer serializer = new XmlSerializer(typeof(ItemCollection)); using (FileStream f = File.Create(fileName)) serializer.Serialize(f, items); 

查看生成的XML后,我看到ItemCollection.Name值不存在!

我认为可能发生的事情是序列化程序将ItemCollection类型看作一个简单的Collection,因此忽略了任何其他添加的属性……

是否有人遇到过这样的问题并找到了解决方案?

问候,

Stécy

此行为是设计使然”。 从集合类派生时,Xml Seralizier将仅序列化集合元素。 要解决这个问题,您应该创建一个封装集合和名称的类,并将其序列化。

 class Wrapper { private Collection _items; private string _name; public Collection Items { get {return _items; } set { _items = value; } } public string Name { get { return _name; } set { _name = value; } } } 

有关详细讨论,请访问: http : //blogs.vertigo.com/personal/chris/Blog/archive/2008/02/01/xml-serializing-a-derived-collection.aspx

XmlSerializer是邪恶的。 也就是说,任何实现IEnumerable的对象都将被序列化为一个简单的集合,忽略您自己添加的任何额外属性。

您需要创建一个包含属性和返回集合的属性的新类。

我不确定我是否遗漏了某些东西,但是你想要得到的xml

  name val  1  2  

如果是这样,只需将XmlRoot属性应用于itemcollection类并设置元素名称…

 [XmlRoot(ElementName="ItemCollection")] public class ItemCollection : Collection { [XmlElement(ElementName="Name")] public string Name {get;set;} } 

这将指示序列化程序为您的集合容器输出所需的名称。

您还可以尝试使用IXmlSerializable接口实现自己的序列化

  public class ItemCollection : Collection,IXmlSerializable { private string _name; public ItemCollection() { _name = string.Empty; } public string Name { get { return _name; } set { _name = value; } } #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { } public void WriteXml(System.Xml.XmlWriter writer) { writer.WriteElementString("name", _name); List coll = new List(this.Items); XmlSerializer serializer = new XmlSerializer(coll.GetType()); serializer.Serialize(writer, coll); } #endregion } 

上面的代码将生成序列化的xml为

      1   2    
 public class Animals : List, IXmlSerializable { private static Type[] _animalTypes;//for IXmlSerializable public Animals() { _animalTypes = GetAnimalTypes().ToArray();//for IXmlSerializable } // this static make you access to the same Animals instance in any other class. private static Animals _animals = new Animals(); public static Animals animals { get {return _animals; } set { _animals = value; } } #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { bool wasEmpty = reader.IsEmptyElement; reader.Read(); if (wasEmpty) return; reader.MoveToContent(); reader.ReadStartElement("Animals"); // you MUST deserialize with 'List', if Animals class has no 'List' fields but has been derived from 'List'. List coll = GenericSerializer.Deserialize>(reader, _animalTypes); // And then, You can set 'Animals' to 'List'. _animals.AddRange(coll); reader.ReadEndElement(); //Read Closing Element reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { writer.WriteStartElement("Animals"); // You change 'List' to 'Animals' at first. List coll = new List(_animals); // And then, You can serialize 'Animals' with 'List'. GenericSerializer.Serialize>(coll, writer, _animalTypes); writer.WriteEndElement(); } #endregion public static List GetAnimalTypes() { List types = new List(); Assembly asm = typeof(Animals).Assembly; Type tAnimal = typeof(Animal); //Query our types. We could also load any other assemblies and //query them for any types that inherit from Animal foreach (Type currType in asm.GetTypes()) { if (!currType.IsAbstract && !currType.IsInterface && tAnimal.IsAssignableFrom(currType)) types.Add(currType); } return types; } }