# 000160. Сериализация и десериализация XML в c\#

Сериализация и десериализация XML в c#||wmysterio|wmysterio|<wmysterio@yandex.ru>|||Доброго времени суток всем пользователям нашего сайта! Сегодня мы изучим одну важную тему как сериализация и обратный её процесс - десириализация. Под этим странным словом "сериализация" скрывается процесс перевода некой информации в поток битов с целью сохранить где-то или восстановить из чего-то. Иными словами - изъять из файла объект или сохранить объект в файл. Для примера мы будем использовать XML-файл для хранения нашего субъекта. Сам объект будет представлен следующим классом, например:<br>

Кодpublic class Car {\
&#x20;   public float Speed;\
&#x20;   public string EngineType;\
&#x20;   public int SeatCount;\
\
&#x20;   public Car() { }\
}Чтобы удобно работать с таким средством, как сериализация, Нам лучше создать ещё один класс, который будет выполнять поставленную задачу. К примеру, назовём его "XMLFile". Чтобы он умел работать со всеми типами данных, ему нужно указать приставку с типом данных на вход:\
Кодpublic class XMLFile\*\*\<T>\*\* {\
\
}Как правило неизвестный тип(или ожидаемый) принято называть как **T**, хотя это никак не влияет общую картину. Так как этот тип нам нужно использовать в методах, которые я запланировал, нам нужно создать поле со стандартным типом **Type**, переменная которой будет заполнятся из конструктора с помощью инструкции typeof, которая как раз и возвращает тип переданного в неё объекта. Что Нам ещё нужно? Естественно - это путь к файлу, иначе куда/откуда будет записывать/читать класс. Наш конструктор будет иметь следующий вид:\
Кодpublic class XMLFile\*\*\<T>\*\* {\
&#x20;  Type dataType;\
&#x20;  string filePath;\
\
&#x20;  public XMLFile( string filePath ) {\
&#x20;     this.filePath = filePath + ".xml";\
&#x20;     dataType = typeof( T );\
&#x20;  }\
}Дальше нам нужно написать две процедуры, которые сериализуют и десириализуют объект соответственно. Первый метод назовём - **Load()**, который десериализует данные из файла и вернёт объект указанного в конструкторе типа.\
\
Стандартный класс **XmlSerializer может получать данные только с потоковыми типами данных, например TextReader или TextWriter, по-этому мы должны создать объект потоковых типов а затем сам десериалайзер:**\
**КодTextReader tr = new StreamReader( filePath ); // открываем поток**\
**XmlSerializer reader = new XmlSerializer( dataType ); // передаём тип T в качестве параметра**\
**Следующим щагом будет создания объекта типа T** и возврат его из метода. Делается это следующим образом:\
Кодreader.Deserialize( tr );\
Как только данные изъяты нам нужно преобразовать его к типу **T**, чтобы наш c# умел с ним обращаться. Наш метод будет таков:\
Кодpublic **T** Load() {\
&#x20;  TextReader tr = new StreamReader( filePath );\
&#x20;  XmlSerializer reader = new XmlSerializer( dataType );\
&#x20;  **T** **instance** = ( **T** ) reader.Deserialize( tr );\
&#x20;  tr.Close(); // обязательно нужно закрывать файловый поток!\
&#x20;  return **instance**;\
}\
Сохранение происходит несколько иным образом, но за похожим принципом. Во-первых: нужно знать объект, который нужно сохранить, по-этому передаём его в качестве параметра процедуры через ключевое слово object. Во-вторых: в качестве файлового потока используем TextWriter, так как мы должны записывать данные.  Для сериализации используем следующий код:\
Кодpublic void Save( object Obj ) {\
&#x20;  TextWriter tw = new StreamWriter( filePath );\
&#x20;  XmlSerializer writer = new XmlSerializer( dataType );\
&#x20;  writer.Serialize( tw, **Obj** );\
&#x20;  tw\.Close();\
}\
Важно! Как уже было сказано, сериализация происходит только с публичными полями. Это значит, что все методы и приватные поля не будут входить в сохраняемый объект.\
\
Наш класс XMLFile иметь такое содержание:\
Кодpublic class XMLFile\<T> {\
&#x20;  Type dataType;\
&#x20;  string filePath;\
\
&#x20;  public XMLFile( string filePath ) {\
&#x20;     this.filePath = filePath + ".xml";\
&#x20;     dataType = typeof( T );\
&#x20;  }\
\
&#x20;  public T Load() {\
&#x20;     TextReader tr = new StreamReader( filePath );\
&#x20;     XmlSerializer reader = new XmlSerializer( dataType );\
&#x20;     T instance = (T) reader.Deserialize( tr );\
&#x20;     tr.Close();\
&#x20;     return instance;\
&#x20;  }\
\
&#x20;  public void Save( object Obj ) {\
&#x20;     TextWriter tw = new StreamWriter( filePath );\
&#x20;     XmlSerializer writer = new XmlSerializer( dataType );\
&#x20;     writer.Serialize( tw, Obj );\
&#x20;     tw\.Close();\
&#x20;  }\
\
}\
Давайте проверим рабоспособность нашего класса. Для этого создадим объект класса Car, который мы написали выше и сохраним его. Наш код будет следующим:\
Код   static void Main( string\[] args ) {\
&#x20;     XMLFile\<Car> file = new XMLFile\<Car>( "save" ); // создаём объект.\
\
&#x20;     Car c = new Car(); // создаём авто и заполняем поля объекта\
&#x20;     c.EngineType = "auto";\
&#x20;     c.SeatCount = 4;\
&#x20;     c.Speed = 25.0f;\
\
&#x20;     file.Save( c ); // сохраняем транспорт\
&#x20;  }\
Проверяем результат:\
[![](https://github.com/wmysterio/scm-scripting-lessons/blob/main/_pu/2/s06072255.jpg)](https://github.com/wmysterio/scm-scripting-lessons/blob/main/_pu/2/06072255.png)\
\
Как мы видим - наш файл преобразовал некое дерево (как обычный xml-документ). Атрибуты "xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>" xmlns:xsd="<http://www.w3.org/2001/XMLSchema>"" можно удалить. Они никак не будут влиять на чтение объекта. Это чтение мы сейчас сделаем, используя следующий код:\
Код   static void Main( string\[] args ) {\
&#x20;     XMLFile\<Car> file = new XMLFile\<Car>( "save" );\
&#x20;     Car c = file.Load(); // получаем объект из файла\
&#x20;     // и выводим информацию об объекте\
&#x20;     Console.WriteLine( "Engine: {0}\nSeat count: {1}\nMax. speed: {2}", c.EngineType, c.SeatCount, c.Speed );\
&#x20;     Console.ReadKey();\
&#x20;  }\
Результат:\
![](https://github.com/wmysterio/scm-scripting-lessons/blob/main/_pu/2/32790903.png)\
\
Дальше в уроке пойдёт речь о некоторых особенностях заполнения xml-документа. В первую очередь это касается списков и массивов. Если наш класс Car будет иметь поле\
Кодpublic List\<string> Author;\
то в таком формате нужно указывать тип, который указан в скобках:\
Код\<Car>\
&#x20; **\<Author>**\
&#x20;   **\<string>Joe MC Dolls\</string>**\
&#x20;   **\<string>El Bolder\</string>**\
&#x20;   **\<string>Mac Todds\</string>**\
&#x20;   **\<string>Jeck Petterson\</string>**\
&#x20;   **\<string>Yang Jedd\</string>**\
&#x20;   **\<string>Poly Ennson\</string>**\
&#x20; **\</Author>**\
&#x20; \<Speed>25\</Speed>\
&#x20; \<EngineType>auto\</EngineType>\
&#x20; \<SeatCount>4\</SeatCount>\
\</Car>\
Второй случай будет касаться массивов. Заполнение не отличаются от списков, но в качестве примера возьмём класс **Car**. Содержимое xml-файла с полем\
Кодpublic Car\[] Cars;\
в классе, например **Test**,будет таковым:\
Код\<Test>\
&#x20; **\<Cars>**\
&#x20;   **\<Car>**\
&#x20;     **\<Speed>25\</Speed>**\
&#x20;     **\<EngineType>auto\</EngineType>**\
&#x20;     **\<SeatCount>4\</SeatCount>**\
&#x20;   **\</Car>**\
&#x20;   **\<Car>**\
&#x20;     **\<Speed>120\</Speed>**\
&#x20;     **\<EngineType>auto\</EngineType>**\
&#x20;     **\<SeatCount>2\</SeatCount>**\
&#x20;   **\</Car>**\
&#x20;   **\<Car>**\
&#x20;     **\<Speed>400\</Speed>**\
&#x20;     **\<EngineType>auto\</EngineType>**\
&#x20;     **\<SeatCount>1\</SeatCount>**\
&#x20;   **\</Car>**\
&#x20; **\</Cars>**\
\</Test>\
Некоторые типы данный нельзя сохранить. Кроме этого, сложные двухмерные массивы или списки имеют другие конструкции. Например: поле\
Кодpublic List\<List\<string>> Autors;как правило заполняется следующим образом:\
Код\<Autors>\
&#x20; \<ArrayOfString>\
&#x20;   \<string>test 0 1\</string>\
&#x20;   \<string>test 0 2\</string>\
&#x20;   \<string>test 0 3\</string>\
&#x20; \</ArrayOfString>\
&#x20; \<ArrayOfString />\
&#x20;   \<string>test 1 1\</string>\
&#x20;   \<string>test 1 2\</string>\
&#x20;   \<string>test 1 3\</string>\
&#x20; \<ArrayOfString />\
\</Autors>\
По-этому, если Вы решились заполнить XML-файл вручную, то лучше сохранить заранее объект а выходной документ использовать в качестве примера для Вашего файла.\
\
Ещё несколько слов о требованию игнорировать некие поля. Как правило игнорируются приватные поля а также те, которые не указаны в XML-файле. Вот простой пример:\
Код\[XmlIgnore]\
public Car Preview;\
\[XmlIgnore]\
string Pattern;\
Нужно немного потренироваться, ничего сложного здесь нет. С Вами был wmysterio. До встречи в новых уроках.\
|3685|1|0|06072255`png`900`146`400`64\|32790903`png`158`123||serializacija\_i\_deserializacija\_xml\_v\_c|1400678655
