c # наследование родовой коллекции и сериализации

Настройка:

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

Теперь, пытаясь сериализовать, используя следующий fragment кода:

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

Посмотрев на полученный XML, я вижу, что значение ItemCollection.Name не существует!

Я думаю, что может произойти, что сериализатор видит тип ItemCollection как простую коллекцию, игнорируя при этом любые другие добавленные свойства …

Кто-нибудь столкнулся с такой проблемой и нашел решение?

С Уважением,

Stécy

Такое поведение является особенностью”. При получении classа коллекции Xml Seralizier будет сериализовывать элементы коллекции. Чтобы обойти это, вы должны создать class, который инкапсулирует коллекцию и имя и будет сериализован.

 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, будет сериализован как простая коллекция, игнорируя любые дополнительные свойства, которые вы добавили сами.

Вам нужно будет создать новый class, который содержит как ваше свойство, так и свойство, возвращающее коллекцию.

Я не уверен, что мне что-то не хватает, но вы хотите, чтобы получившийся xml был

  name val  1  2  

Если это так, просто примените атрибут XmlRoot к classу 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; } }