Сериализация списка <> экспортируется как 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?

7 голосов | спросил PaulH 20 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 20 Sep 2011 22:59:29 +0400 2011, 22:59:29

2 ответа


0

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 и написать свою собственную сериализацию ,

Изменить: Артур Мустафин прав, участники, которые реализуют IEnumerable или ICollection не нужен установщик , как объясняется на эта страница msdn :

  

XmlSerializer предоставляет особый режим для классов, которые реализуют IEnumerable или ICollection. Класс, который реализует IEnumerable, должен реализовывать общедоступный Add метод, который принимает один параметр. Параметр метода Add должен иметь тот же тип, который возвращается из свойства Current для значения, возвращаемого из GetEnumerator или одна из основ этого типа. Класс, который реализует ICollection (например, CollectionBase) в дополнение к IEnumerable должен иметь открытое индексированное свойство Item (индексатор в C #), которое принимает целое число, и оно должно иметь публичное Свойство Count типа integer. Параметр для метода Add должен быть того же типа, который возвращается из Item или одна из основ этого типа. Для классов, которые реализуют ICollection, значения для сериализации извлекаются из индексированного Item, не вызывая GetEnumerator.

ответил Elian Ebbing 20 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 20 Sep 2011 23:28:07 +0400 2011, 23:28:07
0

Предоставляя правильный ответ, нет смысла создавать некрасивый установщик для открытого свойства List<T>, чтобы вызвать исключение.

Это потому, что List<> уже реализует ICollection<T> и предоставляет метод с подписью void Add(T object), который используется механизмом сериализации;

Вам нужно только добавить установщик к сериализуемым общедоступным свойствам и изменить ICollection<T> на 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

ответил Artur Mustafin 30 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 30 Sep 2011 05:31:25 +0400 2011, 05:31:25

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132