Сериализация списка, экспортированного как ICollection в XML
у меня есть приложение C# .NET 3.5, где я хотел бы сериализовать класс, содержащий List<> в XML. Мой класс выглядит так:
[XmlRoot("Foo")]
class Foo
{
private List<Bar> bar_ = new List<Bar>();
private string something_ = "My String";
[XmlElement("Something")]
public string Something { get { return something_; } }
[XmlElement("Bar")]
public ICollection<Bar> Bars
{
get { return bar_; }
}
}
если я заполняю его так:
Bar b1 = new Bar();
// populate b1 with interesting data
Bar b2 = new Bar();
// populate b2 with interesting data
Foo f = new Foo();
f.Bars.Add(b1);
f.Bars.Add(b2);
а затем сериализуйте его следующим образом:
using (System.IO.TextWriter textWriter = new System.IO.StreamWriter(@"C:foo.xml"))
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Foo));
serializer.Serialize(textWriter, f);
}
Я получаю файл, который выглядит так:
<Foo>
<Something>My String</Something>
</Foo>
но, что я хочу-это XML, который выглядит так:
<Foo>
<Something>My String</Something>
<Bar>
<!-- Data from first Bar -->
</Bar>
<Bar>
<!-- Data from second Bar -->
</Bar>
</Foo>
что мне нужно сделать, чтобы получить List<> чтобы появиться в XML?
2 ответов
на XmlSerializer требует, чтобы сериализуемые свойства имели сеттер. Кроме того,XmlSerializer не удается сериализовать свойства интерфейса. Будет работать следующий код:
[XmlElement("Bar")]
public List<Bar> Bars
{
get { return bar_; }
set { throw new NotSupportedException("This property 'Bars' cannot be set. This property is readonly."); }
}
Если вам не нравится это решение (исключение является своего рода уродливым), то вы можете реализовать IXmlSerializable и напишите свою собственную сериализацию.
Edit: Артур Мустафин прав, участники, которые реализуют IEnumerable или ICollection не нужен сеттер, как это объяснил на эта страница msdn:
XmlSerializer дает специальное обращение к классам, которые реализуют
IEnumerableилиICollection. Класс, реализующийIEnumerableдолжен реализовать publicAddметод, который принимает один параметр. Параметр метода Add должен быть того же типа, что и возвращаемый изCurrentсвойство для значения, возвращаемого изGetEnumerator, или одна из баз такого типа. Класс, реализующийICollection(например, CollectionBase) в дополнение кIEnumerableдолжен быть общедоступныйItemиндексированное свойство (индексатор в C#), которое принимает целое число, и оно должно иметь publicCountсвойство типа integer. ПараметрAddметод должен быть того же типа, что возвращается изItemсвойство или одна из баз этого типа. Для классов, реализующихICollection, значения для сериализации извлекаются из индексированногоItemсвойство, не вызываяGetEnumerator.
давая правильный ответ, нет смысла создавать уродливый сеттер для List<T> public property, чтобы создать исключение.
это так List<> уже реализует ICollection<T> и предоставляет метод с подписью void Add(T object) который используется механизмом сериализации;
вам нужно только добавить сеттер к сериализуемым общедоступным свойствам и изменить ICollection<T> to List<T>:
[XmlRoot("Foo")]
public class Foo
{
private List<Bar> bar_ = new List<Bar>();
[XmlElement("Something")]
public string Something { get; set; }
[XmlElement("Bar")]
public List<Bar> Bars { get { return bar_; } }
}
вы получите вывод:
<?xml version="1.0" encoding="utf-8"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Something>My String</Something>
<Bar />
<Bar />
</Foo>
кроме того, лучше сериализовать xml в памяти, чтобы увидеть результаты или проверить его следующим образом:
static void Main(string[] args)
{
Bar b1 = new Bar();
// populate b1 with interesting data
Bar b2 = new Bar();
// populate b2 with interesting data
Foo f = new Foo();
f.Bars.Add(b1);
f.Bars.Add(b2);
f.Something = "My String";
using (MemoryStream ms = new MemoryStream())
using (System.IO.TextWriter textWriter = new System.IO.StreamWriter(ms))
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Foo));
serializer.Serialize(textWriter, f);
string text = Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(text);
}
Console.ReadKey(false);
}
для сериализации с помощью интерфейсов используйте мой проект XmlSerialization