c # наследование универсальной коллекции и сериализации - PullRequest
6 голосов
/ 20 марта 2009

Настройка:

class Item
{
    private int _value;

    public Item()
    {
        _value = 0;
    }

    public int Value { get { return _value; } set { _value = value; } }
}

class ItemCollection : Collection<Item>
{
    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 как простую коллекцию, игнорируя любые другие добавленные свойства ...

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

С уважением,

Stécy

Ответы [ 5 ]

12 голосов
/ 20 марта 2009

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

class Wrapper
{
    private Collection<Item> _items;
    private string _name;

    public Collection<Item> 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

4 голосов
/ 20 марта 2009

XmlSerializer это зло. Тем не менее, любой объект, который реализует IEnumerable, будет сериализован как простая коллекция, игнорируя любые дополнительные свойства, которые вы добавили сами.

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

2 голосов
/ 29 апреля 2010

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

<ItemCollection>
   <Name>name val</Name>
   <Item>
      <Value>1</alue>
   </Item
   <Item>
      <Value>2</alue>
   </Item
</ItemCollection>

Если это так, просто примените атрибут XmlRoot к классу itemcollection и задайте имя элемента ...

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

Это даст указание сериализатору вывести требуемое имя для вашего контейнера сбора.

0 голосов
/ 05 мая 2013
public class Animals : List<Animal>, 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<Animal>', if Animals class has no 'List<Animal>' fields but has been derived from 'List<Animal>'.
        List<Animal> coll = GenericSerializer.Deserialize<List<Animal>>(reader, _animalTypes);
        // And then, You can set 'Animals' to 'List<Animal>'.
        _animals.AddRange(coll);
        reader.ReadEndElement();

        //Read Closing Element
        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteStartElement("Animals");
        // You change 'List<Animal>' to 'Animals' at first.
        List<Animal> coll = new List<Animal>(_animals);
        // And then, You can serialize 'Animals' with 'List<Animal>'.
        GenericSerializer.Serialize<List<Animal>>(coll, writer, _animalTypes);
        writer.WriteEndElement();
    }

    #endregion

    public static List<Type> GetAnimalTypes()
    {
        List<Type> types = new List<Type>();
        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;
    }
}
0 голосов
/ 20 марта 2009

Вы также можете попробовать реализовать свою собственную сериализацию, используя интерфейс IXmlSerializable

    public class ItemCollection : Collection<Item>,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<Item> coll = new List<Item>(this.Items);
              XmlSerializer serializer = new XmlSerializer(coll.GetType());
              serializer.Serialize(writer, coll);

         }

#endregion
   }

Выше кода будет генерировать сериализованный XML как

<?xml version="1.0"?>
<ItemCollection>
  <name />
  <ArrayOfItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Item>
      <Value>1</Value>
    </Item>
    <Item>
      <Value>2</Value>
    </Item>
  </ArrayOfItem>
</ItemCollection>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...