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>
Любые идеи? Чем проще, тем лучше. Спасибо.
Ответы
Ответ 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");
}
}