Когда класс наследуется от List <>, XmlSerializer не сериализует другие атрибуты - PullRequest
18 голосов
/ 21 февраля 2011

У меня здесь ситуация, мне нужно, чтобы мой класс был унаследован от List<ItemType>, но когда я делаю это, XmlSerializer не сериализует никакие свойства или поля, объявленные в моем классе, следующий пример демонстрирует:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        DoSerialize();
    }
    private void DoSerialize()
    {
        MyClass obj = new MyClass();
        obj.Add(1);
        obj.Add(2);
        obj.Add(3);
        XmlSerializer s = new XmlSerializer(typeof(MyClass));
        StringWriter sw = new StringWriter();
        s.Serialize(sw, obj);
    }
}
[Serializable]
[XmlRoot]
public class MyClass : List<int>
{
    public MyClass()
    {
    }
    int myAttribute = 2011;
    [XmlAttribute]
    public int MyAttribute
    {
        get
        {
            return myAttribute;
        }
        set
        {
            myAttribute = value;
        }
    }
}

полученный XML:

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <int>1</int>
  <int>2</int>
  <int>3</int>
</ArrayOfInt>

Ответы [ 2 ]

23 голосов
/ 21 февраля 2011

Это по замыслу. Я не знаю, почему было принято это решение, , но это указано в документации :

  • Классы, которые реализуют ICollection или IEnumerable. Только коллекции сериализованные, не публичные свойства.

(см. Раздел «Элементы, которые можно сериализовать»). Кто-то подал ошибку против этого, но она не будет изменена - здесь Microsoft также подтверждает, что не включение свойств для классов, реализующих ICollection, фактически является поведением XmlSerializer.

Обходной путь может быть либо:

  • Реализуйте IXmlSerializable и управляйте сериализацией самостоятельно.

или

  • Измените MyClass, чтобы он имел открытое свойство типа List (и не делайте его подклассов).

или

  • Используйте DataContractSerializer, который обрабатывает этот сценарий.
3 голосов
/ 23 февраля 2012

Вот вам хотя бы рассмотреть.

У вас может быть класс, который является контейнерным классом, подобным этому:

class ContainerObject
{
     public int MyNewProperty { get; set; }

     [XmlElement("")]
     public List<int> MyList { get; set; }
}

Хитрость заключается в том, чтобы XmlElement name = "" выше элемента List.

Когда это сериализовано в XML, у вас будет:

<ContainerObject>
   <MyNewProperty>...</MyNewProperty>

   <int>...</int>
   <int>...</int>

</ContainerObject>

Если хотите, вы также можете создать еще один класс для элементов в списке

 class MyItem
 {
     public int MyProperty {get;set;} 

 } 

и затем вместо Списка целых есть Список MyItems.

Это вы управляете именем XmlElement для каждого элемента в списке.

Надеюсь, это было полезно.

...