XmlSerialize пользовательская коллекция с атрибутом - PullRequest
18 голосов
/ 18 декабря 2008

У меня есть простой класс, который наследует от Collection и добавляет несколько свойств. Мне нужно сериализовать этот класс в XML, но XMLSerializer игнорирует мои дополнительные свойства.

Я предполагаю, что это из-за особой обработки, которую XMLSerializer предоставляет объектам ICollection и IEnumerable. Как лучше обойти это?

Вот пример кода:

using System.Collections.ObjectModel;
using System.IO;
using System.Xml.Serialization;

namespace SerialiseCollection
{
    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyCollection();
            c.Add("Hello");
            c.Add("Goodbye");

            var serializer = new XmlSerializer(typeof(MyCollection));
            using (var writer = new StreamWriter("test.xml"))
                serializer.Serialize(writer, c);
        }
    }

    [XmlRoot("MyCollection")]
    public class MyCollection : Collection<string>
    {
        [XmlAttribute()]
        public string MyAttribute { get; set; }

        public MyCollection()
        {
            this.MyAttribute = "SerializeThis";
        }
    }
}

При этом выводится следующий XML (обратите внимание, что MyAttribute отсутствует в элементе MyCollection):

<?xml version="1.0" encoding="utf-8"?>
<MyCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <string>Hello</string>
    <string>Goodbye</string>
</MyCollection>

Что я хочу - это

<MyCollection MyAttribute="SerializeThis" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <string>Hello</string>
    <string>Goodbye</string>
</MyCollection>

Есть идеи? Чем проще, тем лучше. Спасибо.

Ответы [ 5 ]

13 голосов
/ 25 марта 2010

Если вы инкапсулируете, как предполагает Марк Гравелл, в начале этого поста объясняется, как сделать так, чтобы ваш XML выглядел точно так, как вы описали.

http://blogs.msdn.com/youssefm/archive/2009/06/12/customizing-the-xml-for-collections-with-xmlserializer-and-datacontractserializer.aspx

То есть вместо этого:

<MyCollection MyAttribute="SerializeThis" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Items>
    <string>Hello</string>
    <string>Goodbye</string>
  <Items>
</MyCollection>

Вы можете иметь это:

<MyCollection MyAttribute="SerializeThis" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">      
  <string>Hello</string>
  <string>Goodbye</string>
</MyCollection>
13 голосов
/ 18 декабря 2008

Коллекции обычно не создают хороших мест для дополнительных свойств. И при сериализации, и при привязке данных они будут игнорироваться, если элемент выглядит как коллекция (IList, IEnumerable и т. Д. - в зависимости от сценария).

Если бы это был я, я бы инкапсулировал коллекцию - т.е.

[Serializable]
public class MyCollectionWrapper {
    [XmlAttribute]
    public string SomeProp {get;set;} // custom props etc
    [XmlAttribute]
    public int SomeOtherProp {get;set;} // custom props etc
    public Collection<string> Items {get;set;} // the items
}

Другой вариант - реализовать IXmlSerializable (довольно много работы), но это все равно не сработает для привязки данных и т. Д. В принципе, это не ожидаемое использование.

1 голос
/ 16 февраля 2015

Как предполагает Нил Уитакер, и в случае, если его ссылка умрет ..

Создайте внутреннюю коллекцию для хранения строк и примените атрибут XmlElement, чтобы замаскировать имя коллекции. Создает тот же вывод xml, как если бы MyCollection унаследовал от Collection, но также сериализует атрибуты родительского элемента.

[XmlRoot("MyCollection")]
public class MyCollection 
{
    [XmlAttribute()]
    public string MyAttribute { get; set; }

    [XmlElement("string")]
    public Collection<string> unserializedCollectionName { get; set; }

    public MyCollection()
    {
        this.MyAttribute = "SerializeThis";
        this.unserializedCollectionName = new Collection<string>();
        this.unserializedCollectionName.Add("Hello");
        this.unserializedCollectionName.Add("Goodbye");
    }
}
0 голосов
/ 25 января 2015

Иногда вы просто хотите делать то, что вы просто хотите; Рамки будь прокляты.

Я разместил ответ здесь Свойство списка Не десериализовано

это делает то, что хотел сделать ОП.

0 голосов
/ 30 декабря 2008

Я боролся с той же проблемой, что и Romaroo (желая добавить свойства в сериализацию xml класса, реализующего ICollection). Я не нашел способ выставить свойства, которые находятся в классе коллекции. Я даже попытался использовать тег XmlAttribute и сделать так, чтобы мои свойства отображались как атрибуты корневого узла, но и там мне не повезло. Однако я смог использовать тег XmlRoot в своем классе, чтобы переименовать его из «ArrayOf ...». Вот несколько ссылок на случай, если вы заинтересованы:

...