Сериализация списка, экспортированного как 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