Сериализация в XML. XmlSerializer

Последнее обновление: 21.02.2022

Для удобного сохранения и извлечения объектов из файлов xml может использоваться класс XmlSerializer из пространства имен System.Xml.Serialization. Данный класс упрощает сохранение сложных объектов в формат xml и последующее их извлечение.

Для создания объекта XmlSerializer можно применять различные конструкторы, но почти все они требуют указания типа данных, которые будут сериализоваться и десериализоваться:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));

//[Serializable]
class Person { }

В данном случае XmlSerializer будет работать только с объектами класса Person.

Следует учитывать, что XmlSerializer предполагает некоторые ограничения. Например, класс, подлежащий сериализации, должен иметь стандартный конструктор без параметров и должен иметь модификатор доступа public. Также сериализации подлежат только открытые члены. Если в классе есть поля или свойства с модификатором private, то при сериализации они будут игнорироваться. Кроме того, свойства должны иметь общедоступные геттеры и сеттеры.

Сериализация

Для сериализации (то есть сохранения в форма xml) применяется метод Serialize(). Данный метод имеет ряд версий. Возьмем самую простую из них:

void Serialize (Stream stream, object? o);

В качестве первого параметра передается поток Stream (например, объект FileStream), в который будет идти сериализация. А второй параметр представляет собственно тот объект, который будет сохраняться в формат xml. Например:

using System.Xml.Serialization;

// объект для сериализации
Person person = new Person("Tom", 37);

// передаем в конструктор тип класса Person
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));

// получаем поток, куда будем записывать сериализованный объект
using (FileStream fs = new FileStream("person.xml", FileMode.OpenOrCreate))
{
    xmlSerializer.Serialize(fs, person);

    Console.WriteLine("Object has been serialized");
}

//[Serializable]
public class Person
{
    public string Name { get; set; } = "Undefined";
    public int Age { get; set; } = 1;

    public Person() { }
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Итак, класс Person общедоступный, имеет общедоступные свойства и конструктор без параметров, поэтому объекты этого класса подлежат сериализации. При создании объекта XmlSerializer передаем в конструктор тип класса Person.

В метод Serialize передается файловый поток для сохранения данных в файл person.xml и сохраняемый в этот файл объект Person. И если по завершению программы мы откроем файл person.xml, то увидим содержание нашего объекта:

<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Tom</Name>
  <Age>37</Age>
</Person>

Десериализация

Для десериализации данных xml в объект кода C# применяется метод Deserialize(). Отметим одну из версий этого метода:

object? Deserialize (Stream stream);

В качестве параметра в метод передается объект Stream, который содержит данные в формате xml. Результатом метода является десериализованный объект.

Например, десериализуем данные из выше созданного файла person.xml:

using System.Xml.Serialization;

XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));

// десериализуем объект
using (FileStream fs = new FileStream("person.xml", FileMode.OpenOrCreate))
{
    Person? person = xmlSerializer.Deserialize(fs) as Person;
    Console.WriteLine($"Name: {person?.Name}  Age: {person?.Age}");
}

public class Person
{
    public string Name { get; set; } = "Undefined";
    public int Age { get; set; } = 1;

    public Person() { }
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Сериализация и десериализация коллекций

Подобным образом мы можем сериализовать массив или коллекцию объектов:

using System.Xml.Serialization;

Person[] people = new Person[]
{
    new Person("Tom", 37),
    new Person("Bob", 41)
};

XmlSerializer formatter = new XmlSerializer(typeof(Person[]));
// сохранение массива в файл
using (FileStream fs = new FileStream("people.xml", FileMode.OpenOrCreate))
{
    formatter.Serialize(fs, people);
}
// восстановление массива из файла
using (FileStream fs = new FileStream("people.xml", FileMode.OpenOrCreate))
{
    Person[]? newpeople = formatter.Deserialize(fs) as Person[];

    if(newpeople != null)
    {
        foreach (Person person in newpeople)
        {
            Console.WriteLine($"Name: {person.Name} --- Age: {person.Age}");
        }
    }
}

public class Person
{
    public string Name { get; set; } = "Undefined";
    public int Age { get; set; } = 1;

    public Person() { }
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Консольный вывод:

Name: Tom --- Age: 37
Name: Bob --- Age: 41

Но это был простой объект. Однако с более сложными по составу объектами работать так же просто. Например:

using System.Xml.Serialization;

var microsoft = new Company("Microsoft");
var google = new Company("Google");

Person[] people = new Person[]
{
    new Person("Tom", 37, microsoft),
    new Person("Bob", 41, google)
};

XmlSerializer formatter = new XmlSerializer(typeof(Person[]));

using (FileStream fs = new FileStream("people.xml", FileMode.OpenOrCreate))
{
    formatter.Serialize(fs, people);
}

using (FileStream fs = new FileStream("people.xml", FileMode.OpenOrCreate))
{
    Person[]? newpeople = formatter.Deserialize(fs) as Person[];

    if(newpeople != null)
    {
        foreach (Person person in newpeople)
        {
            Console.WriteLine($"Name: {person.Name}");
            Console.WriteLine($"Age: {person.Age}");
            Console.WriteLine($"Company: {person.Company.Name}");
        }
    }
}

public class Company
{
    public string Name { get; set; } = "Undefined";

    // стандартный конструктор без параметров
    public Company() { }

    public Company(string name) => Name = name;
}
public class Person
{
    public string Name { get; set; } = "Undefined";
    public int Age { get; set; } = 1;
    public Company Company { get; set; } = new Company();

    public Person() { }
    public Person(string name, int age, Company company)
    {
        Name = name;
        Age = age;
        Company = company;
    }
}

Класс Person содержит свойство Company, которое будет хранить объект класса Company. Члены класса Company объявляются с модификатором public, кроме того также присутствует стандартный конструктор без параметров. В итоге после сериализации мы получим следующий xml-документ:

<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Person>
    <Name>Tom</Name>
    <Age>37</Age>
    <Company>
      <Name>Microsoft</Name>
    </Company>
  </Person>
  <Person>
    <Name>Bob</Name>
    <Age>41</Age>
    <Company>
      <Name>Google</Name>
    </Company>
  </Person>
</ArrayOfPerson>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850