Подтвердить что ты не робот

XmlSerialize пользовательская коллекция с атрибутом

У меня есть простой класс, который наследуется от 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>

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

4b9b3361

Ответ 1

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

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

[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 (довольно много работы), но это все равно не будет работать для привязки данных и т.д. В принципе, это не ожидаемое использование.

Ответ 2

Если вы инкапсулируете, как предполагает Марк Гравелл, начало этого сообщения объясняет, как заставить ваш 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>

Ответ 3

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

Ответ 4

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

Я разместил здесь ответ Свойство списка <T> Не deserialized

делает то, что хотел сделать OP.

Ответ 5

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

Создайте внутреннюю коллекцию для хранения строк и примените атрибут 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");
    }
}