Код сериализации объектов

Создано: 18 января 2025 г.

Отвечено с использованием OpenAI 01 от OpenAI01

Вопрос

Я изучаю код. Объясни его как можно более подробно.
Задание, выполняющий код:
1. Из лабораторной №4
композицией/агрегацией
выберите класс с наследованием и/или
для
сериализации.
сериализацию/десериализацию объекта используя форматы:
a. Binary,
b. SOAP,
c. JSON,
d. XML.
Выполните
Запретите сериализацию одного из членов вашего класса и
продемонстрируйте отсутствие данного элемента в результате работы
сериализаторов
Все сериализаторы должен реализовывать общий интерфейс. Выбор и
использование сериализатора следует реализовать таким образом, чтобы
добавление нового сериализатора не требовало изменения существующего
кода
* Усложненное задание:
Создайте класс CustomSerializer, который обеспечивает сериализацию и
десериализацию любых объектов любых типов всеми
вышеперечисленными способами. Интерфейс класса и параметры
методов продумайте самостоятельно.
2. Создайте
коллекцию
(массив)
объектов
и
выполните
сериализацию/десериализацию – возможность сохранения и загрузки
спсика объектов в/из файла.
* Усложненное задание:
Создайте клиент и сервер на синхронных сокетах.
Нужно сериализованные данные(объект) отправить по сокету и
десериализовать на стороне клиента.
3. Используя XPath напишите два селектора для вашего XML документа.
4. Используя Linq to XML (или Linq to JSON) создайте новый xml (json) -
документ и напишите несколько запросов.
Код:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
using Newtonsoft.Json;

// Общий интерфейс для сериализаторов
public interface ISerializer
{
string Serialize(object obj);
T Deserialize<T>(string data);
}

// Класс с наследованием, содержащий запрещенное поле для сериализации
[Serializable]
public class Country
{
public string Name { get; set; }
public int Rank { get; set; }
[NonSerialized] // Запрет на сериализацию этого поля
public string Password;

public Country() { } // Пустой конструктор для десериализации

public Country(string name, int number, string password)
{
Name = name;
Rank = number;
Password = password;
}
}

[Serializable]
public class CountryList
{
public Country[] Countries { get; set; } // Использование массива вместо List

public CountryList()
{
Countries = new Country[0]; // Инициализация пустым массивом
}

public static CountryList FromList(List<Country> countryList)
{
return new CountryList { Countries = countryList.ToArray() }; // Преобразование в массив
}

public List<Country> ToList()
{
return new List<Country>(Countries); // Преобразование обратно в список
}
}

// Сериализатор для JSON
public class JsonSerializer : ISerializer
{
public string Serialize(object obj) => JsonConvert.SerializeObject(obj);

public T Deserialize<T>(string data) => JsonConvert.DeserializeObject<T>(data);
}

// Сериализатор для XML
public class XmlSerializer : ISerializer
{
public string Serialize(object obj)
{
var xmlSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
var stringWriter = new StringWriter();
xmlSerializer.Serialize(stringWriter, obj);
return stringWriter.ToString();
}

public T Deserialize<T>(string data)
{
var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
var stringReader = new StringReader(data);
return (T)xmlSerializer.Deserialize(stringReader);
}
}

// Сериализатор для SOAP
public class SoapSerializer : ISerializer
{
public string Serialize(object obj)
{
using (var memoryStream = new MemoryStream())
{
IFormatter formatter = new SoapFormatter();
formatter.Serialize(memoryStream, obj);
return Convert.ToBase64String(memoryStream.ToArray());
}
}

public T Deserialize<T>(string data)
{
var bytes = Convert.FromBase64String(data);
using (var memoryStream = new MemoryStream(bytes))
{
IFormatter formatter = new SoapFormatter();
return (T)formatter.Deserialize(memoryStream);
}
}
}


public class Program
{
public static void Main()
{
var countryList = new List<Country>
{
new Country("Russia", 10, "secret_password"),
new Country("Belarus", 20, "another_password"),
new Country("China", 5, "mypassword")
};

// Преобразуем список в класс-обертку
var wrappedCountryList = CountryList.FromList(countryList);

// Используем SOAP сериализатор
ISerializer soapSerializer = new SoapSerializer();
string soapData = soapSerializer.Serialize(wrappedCountryList);
Console.WriteLine("SOAP Serialized: " + soapData);

// Запись SOAP в файл
File.WriteAllText("countrys.soap", soapData);

// Десериализация коллекции
var deserializedCountryList = soapSerializer.Deserialize<CountryList>(soapData);
Console.WriteLine("Deserialized Countries from SOAP:");

// Печатаем результат десериализации
foreach (var country in deserializedCountryList.ToList())
{
Console.WriteLine($"Name: {country.Name}, Rank: {country.Rank}, Password: {country.Password}");
}

// Используем JSON сериализатор
ISerializer jsonSerializer = new JsonSerializer();
string jsonData = jsonSerializer.Serialize(countryList);
Console.WriteLine("JSON Serialized: " + jsonData);

// Запись JSON в файл
File.WriteAllText("countrys.json", jsonData);

// Чтение JSON из файла и десериализация
string jsonFromFile = File.ReadAllText("countrys.json");
var deserializedPeopleJson = jsonSerializer.Deserialize<List<Country>>(jsonFromFile);

Console.WriteLine("Deserialized from JSON:");
foreach (var countrie in deserializedPeopleJson)
{
Console.WriteLine($"{countrie.Name}, {countrie.Rank}");
}

// Используем XML сериализатор
ISerializer xmlSerializer = new XmlSerializer();
string xmlData = xmlSerializer.Serialize(countryList);
Console.WriteLine("XML Serialized: " + xmlData);

// Запись XML в файл
File.WriteAllText("countrys.xml", xmlData);

// Чтение XML из файла и десериализация
string xmlFromFile = File.ReadAllText("countrys.xml");
var deserializedPeopleXml = xmlSerializer.Deserialize<List<Country>>(xmlFromFile);

Console.WriteLine("Deserialized from XML:");
foreach (var countrie in deserializedPeopleXml)
{
Console.WriteLine($"{countrie.Name}, {countrie.Rank}");
}

string filePath = "countrys.xml";
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
using (var writer = new StreamWriter(fs, new System.Text.UnicodeEncoding()))
{
writer.Write("<?xml version=\"1.0\" encoding=\"UTF-16\"?>");
writer.Write("<Countrys>");
writer.Write("<Country>");
writer.Write("<Name>Russia</Name>");
writer.Write("<Rank>10</Rank>");
writer.Write("<Password>secret_password</Password>");
writer.Write("</Country>");
writer.Write("</Countrys>");
}


XDocument xdoc;
try
{
xdoc = XDocument.Load(filePath);

var countryNames = xdoc.XPathSelectElements("//Country/Name");
Console.WriteLine("Все названия стран:");
foreach (var name in countryNames)
{
Console.WriteLine(name.Value);
}


var countriesWithHighRank = xdoc.XPathSelectElements("//Country[Rank > 5]/Name");
Console.WriteLine("\nСтраны с рангом больше 5:");
foreach (var name in countriesWithHighRank)
{
Console.WriteLine(name.Value);
}
}
catch (XmlException ex)
{
Console.WriteLine("Ошибка при загрузке XML: " + ex.Message);
}

var states = new XElement("Countrys",
new XElement("Country",
new XElement("Name", "Russia"),
new XElement("Rank", 10),
new XElement("Password", "secret_password")),
new XElement("Country",
new XElement("Name", "Belarus"),
new XElement("Rank", 20),
new XElement("Password", "another_password")),
new XElement("Country",
new XElement("Name", "China"),
new XElement("Age", 5),
new XElement("Password", "mypassword")
)
);


states.Save("countrys.xml");


var names = from state in states.Elements("Country")
select state.Element("Name").Value;

Console.WriteLine("\nAll names:");
foreach (var name in names)
{
Console.WriteLine(name);
}


var worserThan15 = from state in states.Elements("Country")
let rank = (int)state.Element("Rank")
where rank > 15
select state.Element("Name").Value;

Console.WriteLine("Rank worser than 15:");
foreach (var name in worserThan15)
{
Console.WriteLine(name);
}


}
}
Чем подробнее объяснишь, тем лучше

Мысль

Breaking down the assignment

OK, let's see. The task involves demonstrating composition and aggregation, implementing inheritance, serializing data in various formats, and using XPath and LINQ for XML and JSON.

Thought about сериализация и десериализация для несколько секунд

Ответ

Ниже приведён подробный разбор кода и пояснение к его работе, разбитое на логические блоки, чтобы вы могли понимать, что и где происходит.


1. Общая идея задания

  1. Нужно продемонстрировать сериализацию и десериализацию объектов в разные форматы:

    • Binary (в коде не реализован, но в задании упомянут),
    • SOAP,
    • JSON,
    • XML.
  2. При этом один из членов класса должен быть закрыт от сериализации (запрещено сериализовать). В коде это поле Password с атрибутом [NonSerialized].

  3. Все сериализаторы (JSON, XML, SOAP и т.д.) должны реализовывать единый интерфейс (в коде это интерфейс ISerializer), чтобы можно было легко подключать или заменять сериализаторы, не меняя основного кода.

  4. Нужно выполнить:

    • Создание/чтение коллекции объектов,
    • Сохранение/загрузка этих объектов из файлов,
    • Демонстрация того, что одно из полей (Password) не сериализуется,
    • Применение XPath и LINQ to XML/JSON для выборок из результирующего XML (и/или JSON).

В коде есть все необходимые части:

  • Класс Country с запрещённым к сериализации полем,
  • Класс-обёртка CountryList для удобства сериализации массива,
  • Реализация трёх сериализаторов: JsonSerializer, XmlSerializer, SoapSerializer (все имплементируют ISerializer),
  • Основной метод Main, где демонстрируется работа с этими сериализаторами и чтение/запись в файлы,
  • Пример XPath-запросов и LINQ to XML-запросов.

2. Интерфейс ISerializer

public interface ISerializer { string Serialize(object obj); T Deserialize<T>(string data); }
  • Интерфейс определяет две операции, которые должен уметь делать каждый сериализатор:
    1. Serialize – принимает объект (object obj) и возвращает строку (string), где будет содержаться результат сериализации (например, JSON-строка, XML-строка, SOAP-строка).
    2. Deserialize – принимает строку и преобразует её в объект типа T.

Благодаря такому интерфейсу мы можем, не меняя основного кода, подставлять любой класс-сериализатор. Все классы, реализующие ISerializer, будут иметь одинаковые методы (Serialize и Deserialize), но внутри них логика будет отличаться (JSON, XML, SOAP).


3. Класс Country с запрещённым полем

[Serializable] public class Country { public string Name { get; set; } public int Rank { get; set; } [NonSerialized] // Запрет на сериализацию этого поля public string Password; public Country() { } // Пустой конструктор для десериализации public Country(string name, int number, string password) { Name = name; Rank = number; Password = password; } }
  • Атрибут [Serializable] говорит, что этот класс может участвовать в механизмe сериализации (в частности, используется SOAP- и Binary-сериализациями .NET).
  • Поле Password помечено атрибутом [NonSerialized].
    Это значит, что при использовании бинарной или SOAP сериализации, данное поле не будет включено в результирующий поток данных.
    Для XML и JSON сериализации (через XmlSerializer и Json.NET) чуть другие механизмы, но в нашем случае XmlSerializer и JsonConvert тоже не запишут это поле, поскольку для атрибута NonSerialized (и при работе с XmlSerializer, если поле не имеет get; set;) оно чаще всего будет пропущено.
    В любом случае мы демонстрируем запрет сериализации этого поля. Если бы вы захотели скрывать поле от JSON/XML, можно было бы использовать атрибуты вроде [JsonIgnore], [XmlIgnore] и т.д.

4. Класс-обёртка CountryList

[Serializable] public class CountryList { public Country[] Countries { get; set; } // Использование массива вместо List public CountryList() { Countries = new Country[0]; } public static CountryList FromList(List<Country> countryList) { return new CountryList { Countries = countryList.ToArray() }; } public List<Country> ToList() { return new List<Country>(Countries); } }
  • Задача этого класса – упростить сериализацию/десериализацию списка (List<Country>).
  • При использовании SOAP или XML сериализатора классически удобнее сериализовать массив или собственный класс-обёртку, чем напрямую List<T>.
  • Методы FromList и ToList помогают «конвертировать»:
    • Из List<Country> в Country[] (для удобства сериализации),
    • Обратно из Country[] в List<Country> (для удобства использования в коде).

5. Реализация сериализаторов

5.1 JSON-сериализатор (через Json.NET)

public class JsonSerializer : ISerializer { public string Serialize(object obj) => JsonConvert.SerializeObject(obj); public T Deserialize<T>(string data) => JsonConvert.DeserializeObject<T>(data); }
  • В методе Serialize используется метод JsonConvert.SerializeObject(obj), который превращает объект в JSON-строку.
  • В методе Deserialize используется метод JsonConvert.DeserializeObject<T>(data), который из JSON-строки создаёт обратно объект указанного типа T.

Обратите внимание, что мы используем библиотеку Newtonsoft.Json (подключается обычно через NuGet).


5.2 XML-сериализатор (через встроенный System.Xml.Serialization.XmlSerializer)

public class XmlSerializer : ISerializer { public string Serialize(object obj) { var xmlSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); var stringWriter = new StringWriter(); xmlSerializer.Serialize(stringWriter, obj); return stringWriter.ToString(); } public T Deserialize<T>(string data) { var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); var stringReader = new StringReader(data); return (T)xmlSerializer.Deserialize(stringReader); } }
  • В Serialize:

    1. Создаётся XmlSerializer (класс из System.Xml.Serialization), которому передаётся тип сериализуемого объекта.
    2. Создаётся StringWriter, куда XmlSerializer запишет результат в XML-формате.
    3. Возвращаем строковое представление XML.
  • В Deserialize:

    1. Аналогично создаётся XmlSerializer на тип T.
    2. Используется StringReader для чтения XML-строки.
    3. Вызывается метод Deserialize, который из XML-строки «собирает» объект заданного типа.

5.3 SOAP-сериализатор

public class SoapSerializer : ISerializer { public string Serialize(object obj) { using (var memoryStream = new MemoryStream()) { IFormatter formatter = new SoapFormatter(); formatter.Serialize(memoryStream, obj); return Convert.ToBase64String(memoryStream.ToArray()); } } public T Deserialize<T>(string data) { var bytes = Convert.FromBase64String(data); using (var memoryStream = new MemoryStream(bytes)) { IFormatter formatter = new SoapFormatter(); return (T)formatter.Deserialize(memoryStream); } } }
  • В .NET SOAP-сериализация выполняется через класс SoapFormatter.
  • Serialize:
    1. Создаём MemoryStream.
    2. Создаём SoapFormatter.
    3. Сериализуем объект в поток memoryStream.
    4. Превращаем байты из потока в строку с помощью Convert.ToBase64String(...). Это нужно, чтобы удобно было выводить/хранить сериализованные данные в виде «текстовой строки».
  • Deserialize:
    1. Принимаем строку, делаем Convert.FromBase64String, чтобы получить исходный массив байтов.
    2. Помещаем байты в MemoryStream.
    3. Вызываем у SoapFormatter метод Deserialize и приводим результат к типу T.

6. Метод Main и основная демонстрация

public static void Main() { // Создаём список стран var countryList = new List<Country> { new Country("Russia", 10, "secret_password"), new Country("Belarus", 20, "another_password"), new Country("China", 5, "mypassword") }; // Преобразуем список в класс-обертку var wrappedCountryList = CountryList.FromList(countryList); // Используем SOAP сериализатор ISerializer soapSerializer = new SoapSerializer(); string soapData = soapSerializer.Serialize(wrappedCountryList); Console.WriteLine("SOAP Serialized: " + soapData); // Запись SOAP в файл File.WriteAllText("countrys.soap", soapData); // Десериализация коллекции var deserializedCountryList = soapSerializer.Deserialize<CountryList>(soapData); Console.WriteLine("Deserialized Countries from SOAP:"); // Печатаем результат десериализации foreach (var country in deserializedCountryList.ToList()) { Console.WriteLine($"Name: {country.Name}, Rank: {country.Rank}, Password: {country.Password}"); } ... }
  1. Создаётся список List<Country> с тремя странами. Каждая страна имеет поля:

    • Name ("Russia", "Belarus", "China"),
    • Rank (10, 20, 5),
    • Password ("secret_password", "another_password", "mypassword").
  2. Оборачиваем список countryList в объект CountryList (метод FromList), поскольку для SOAP-сериализации (и вообще для части сериализаторов) удобнее работать с классом, а не напрямую со списком.

  3. Soap-сериализация:

    • Создаём объект SoapSerializer.
    • Вызываем soapSerializer.Serialize(wrappedCountryList), результат кладём в строку soapData.
    • Печатаем на экран.
    • Записываем полученную строку (которая на самом деле Base64-представление SOAP) в файл countrys.soap.
  4. Soap-десериализация:

    • Берём soapData (либо могли бы взять из файла).
    • Делаем deserializedCountryList = soapSerializer.Deserialize<CountryList>(soapData).
    • Получаем объект CountryList.
    • С помощью deserializedCountryList.ToList() превращаем его в List<Country>.
    • Выводим значения полей: видим, что поле Password (если SOAP учёл атрибут [NonSerialized]) будет null или пустым (зависит от поведения при десериализации).

Далее аналогично идёт демонстрация JSON и XML сериализации:

6.1 JSON-сериализация и запись в файл

// Используем JSON сериализатор ISerializer jsonSerializer = new JsonSerializer(); string jsonData = jsonSerializer.Serialize(countryList); Console.WriteLine("JSON Serialized: " + jsonData); // Запись JSON в файл File.WriteAllText("countrys.json", jsonData); // Чтение JSON из файла и десериализация string jsonFromFile = File.ReadAllText("countrys.json"); var deserializedPeopleJson = jsonSerializer.Deserialize<List<Country>>(jsonFromFile); Console.WriteLine("Deserialized from JSON:"); foreach (var countrie in deserializedPeopleJson) { Console.WriteLine($"{countrie.Name}, {countrie.Rank}"); }
  • Обратите внимание, что здесь мы сериализуем не wrappedCountryList, а просто List<Country>. С Json.NET можно делать и так, никаких проблем.
  • Записываем результат в countrys.json, потом оттуда читаем.
  • Выводим результат.

6.2 XML-сериализация и запись в файл

// Используем XML сериализатор ISerializer xmlSerializer = new XmlSerializer(); string xmlData = xmlSerializer.Serialize(countryList); Console.WriteLine("XML Serialized: " + xmlData); // Запись XML в файл File.WriteAllText("countrys.xml", xmlData); // Чтение XML из файла и десериализация string xmlFromFile = File.ReadAllText("countrys.xml"); var deserializedPeopleXml = xmlSerializer.Deserialize<List<Country>>(xmlFromFile); Console.WriteLine("Deserialized from XML:"); foreach (var countrie in deserializedPeopleXml) { Console.WriteLine($"{countrie.Name}, {countrie.Rank}"); }
  • То же самое, но с помощью XmlSerializer.
  • Запись в файл countrys.xml, чтение оттуда, вывод.

7. Работа с XPath

После того как мы продемонстрировали сериализацию/десериализацию, идёт пример вставки XML вручную и работы с ним через XPath.

string filePath = "countrys.xml"; using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) using (var writer = new StreamWriter(fs, new System.Text.UnicodeEncoding())) { writer.Write("<?xml version=\"1.0\" encoding=\"UTF-16\"?>"); writer.Write("<Countrys>"); writer.Write("<Country>"); writer.Write("<Name>Russia</Name>"); writer.Write("<Rank>10</Rank>"); writer.Write("<Password>secret_password</Password>"); writer.Write("</Country>"); writer.Write("</Countrys>"); }
  • Здесь код принудительно записывает XML в файл countrys.xml, заменяя то, что было до этого.

  • Получается следующая структура:

    <?xml version="1.0" encoding="UTF-16"?> <Countrys> <Country> <Name>Russia</Name> <Rank>10</Rank> <Password>secret_password</Password> </Country> </Countrys>

Далее идёт код:

XDocument xdoc; try { xdoc = XDocument.Load(filePath); var countryNames = xdoc.XPathSelectElements("//Country/Name"); Console.WriteLine("Все названия стран:"); foreach (var name in countryNames) { Console.WriteLine(name.Value); } var countriesWithHighRank = xdoc.XPathSelectElements("//Country[Rank > 5]/Name"); Console.WriteLine("\nСтраны с рангом больше 5:"); foreach (var name in countriesWithHighRank) { Console.WriteLine(name.Value); } } catch (XmlException ex) { Console.WriteLine("Ошибка при загрузке XML: " + ex.Message); }
  • XDocument.Load(filePath) – загружает XML-документ из файла.
  • XPathSelectElements("//Country/Name") – находит все элементы <Name> внутри <Country> в любом месте XML (путь //Country/Name).
  • Выводим значение name.Value для каждого найденного элемента – получаем «Russia».
  • XPathSelectElements("//Country[Rank > 5]/Name") – находит все <Country> с условием, что значение <Rank> внутри них больше 5, и у этих элементов берёт <Name>.
    • Поскольку у нас Rank = 10 для Russia, это удовлетворяет Rank > 5.
    • Выведется «Russia».

8. Работа с LINQ to XML

Далее идёт код:

var states = new XElement("Countrys", new XElement("Country", new XElement("Name", "Russia"), new XElement("Rank", 10), new XElement("Password", "secret_password")), new XElement("Country", new XElement("Name", "Belarus"), new XElement("Rank", 20), new XElement("Password", "another_password")), new XElement("Country", new XElement("Name", "China"), new XElement("Age", 5), new XElement("Password", "mypassword") ) ); states.Save("countrys.xml");
  • Здесь мы создаём вручную структуру XML (через объекты XElement), которая будет иметь корень <Countrys> и внутри три <Country>.
  • У China для демонстрации вставлено поле <Age> вместо <Rank> (скорее всего, чтобы показать, что можно произвольно изменять структуру).
  • Затем сохраняем states в файл countrys.xml.

8.1 LINQ-запросы к созданному XML

var names = from state in states.Elements("Country") select state.Element("Name").Value; Console.WriteLine("\nAll names:"); foreach (var name in names) { Console.WriteLine(name); } var worserThan15 = from state in states.Elements("Country") let rank = (int)state.Element("Rank") where rank > 15 select state.Element("Name").Value; Console.WriteLine("Rank worser than 15:"); foreach (var name in worserThan15) { Console.WriteLine(name); }
  1. from state in states.Elements("Country") – берём все дочерние элементы <Country> из корневого <Countrys>.
  2. select state.Element("Name").Value – берём значение <Name> для каждой страны.
    • Итого получим последовательность с названиями стран: «Russia», «Belarus», «China».
  3. Выводим все названия.
  4. Следующий запрос:
    • Вводим переменную rank = (int)state.Element("Rank").
      Обратите внимание, что у China вместо <Rank> стоит <Age>, поэтому для него state.Element("Rank") вернёт null, и при попытке (int)null будет исключение (в реальном коде нужно обрабатывать или проверять, что элемент не null). Но тут демонстрационный пример.
    • where rank > 15 — выбираем только те, у кого Rank больше 15. По структуре XML это будет у «Belarus» (Rank = 20).
    • Выводим название страны.
      В итоге выведется: «Belarus».

9. Итоги и ключевые моменты

  1. Интерфейс ISerializer позволяет подменять разные реализации сериализаторов (JSON, XML, SOAP) без изменения остального кода.
  2. Класс Country – демонстрирует атрибут [NonSerialized] на поле Password, которое (в классической сериализации .NET, например SOAP или Binary) не будет сохранено.
  3. Класс CountryList – служит удобной обёрткой для массивов (или списков), чтобы проще передавать их в методы сериализаторов (особенно для SOAP- и XmlSerializer).
  4. В Main:
    • Создаём список объектов Country.
    • Демонстрируем сериализацию/десериализацию:
      • SOAP (в файл countrys.soap),
      • JSON (в файл countrys.json),
      • XML (в файл countrys.xml).
    • После каждой сериализации проверяем, что поле Password при десериализации исчезает (или null), тем самым показав запрет на сериализацию.
  5. Использование XDocument и XPath:
    • Позволяет парсить и выбирать нужные узлы из XML при помощи XPath-запросов, таких как //Country/Name или //Country[Rank > 5]/Name.
  6. LINQ to XML:
    • Позволяет легко создавать новый XML-документ в памяти (класс XElement) и выполнять к нему LINQ-запросы, похожие на SQL по синтаксису (from ... select ...).

Это даёт полное решение по части задания: есть сериализация в несколько форматов, есть пример работы с XML через XPath и LINQ to XML/JSON, а также продемонстрирован механизм исключения поля (Password) из сериализации.


Дополнительные моменты

  • Binary-сериализация не показана в коде, но её можно было бы сделать очень похожим образом на SoapSerializer, только использовать BinaryFormatter (но в более новых версиях .NET она уже не рекомендуется).
  • Для скрытия поля от XmlSerializer и/или Json.NET можно было бы дополнительно использовать [XmlIgnore] и [JsonIgnore].
    В данном коде благодаря тому, что поле Password не является свойством с { get; set; }, а лишь обычным public string, оно часто уже не будет сериализовываться XmlSerializer’ом. Но тут могут быть тонкости.
  • При работе с SOAP поле Password точно не будет сериализовано благодаря [NonSerialized].

Заключение

Таким образом, код выполняет все основные пункты задания:

  1. Класс с наследованием/композицией продемонстрирован (у нас есть класс CountryList и Country).
  2. Запрет сериализации поля Password показан через атрибут [NonSerialized].
  3. Реализованы сериализаторы:
    • SOAP,
    • JSON (через JsonConvert),
    • XML (через XmlSerializer).
      (Binary упомянут в теории задания, но не показан в коде.)
  4. Данные коллекции (List<Country>) сериализуются и десериализуются, сохраняются в файлы.
  5. Выполнены XPath-запросы и LINQ to XML-запросы для демонстрации выборки данных из XML.

Поделиться этим Q&A