На сегодняшний день JSON входит в число основных форматов представления сложных структур и обмена данными. Поэтому все основные языки программирования имеют встроенную поддержку для работы с ним. C# не исключение.
Сериализация в JSON
Существует два основных способа преобразования (сериализации) объектов .NET в JSON:
- Использование класса DataContractJsonSerializer;
- Использование класса JavaScriptSerializer.
Использование класса DataContractJsonSerializer
Класс DataContractJsonSerializer сериализует объекты .NET в поток (Stream) в виде текста в формате JSON или XML сопоставимый с JSON.
Для того чтобы сериализация объекта стала возможна он должен быть отмечен атрибутом DataContract, а его члены подлежащие сериализации атрибутом DataMember. Чтобы эти атрибуты и сам класс DataContractJsonSerializer стали доступны, необходимо подключить к проекту сборку System.Runtime.Serialization.
В качестве примера создадим класс, который описывает организацию.
1 2 3 4 5 6 7 8 9 10 |
[DataContract] class Company { [DataMember] public string Name { get; set; } [DataMember] public string INN { get; set; } [DataMember] public string Adress { get; set; } } |
Создадим объект класса DataContractJsonSerializer для сериализации объектов класса Company.
1 |
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Company)); |
Обратите внимание. Сериализуемый тип передаётся в качестве параметра конструктора.
Далее необходимо создать поток для сериализованных данных.
1 |
MemoryStream stream = new MemoryStream(); |
Или XmlWriter для XML сопоставимого с JSON. Например:
1 |
XmlWriter writer = new XmlTextWriter("test.xml", null); |
Сам процесс сериализации осуществляется с помощью метода WriteObject класса DataContractJsonSerializer. В качестве первого параметра ему передаётся либо поток, либо объект XmlWriter. В качестве второго параметра сериализуемый объект.
В итоге получается или поток с текстом в формате JSON.
1 |
serializer.WriteObject(stream, company); |
Или XML сопоставимый с JSON.
1 2 |
serializer.WriteObject(writer, company); writer.Close(); |
Использование класса JavaScriptSerializer
Класс JavaScriptSerializer расположен в пространстве имён System.Web.Script.Serialization (требует подключения сборки System.Web.Extensions).
Его отличительная особенность в том, что он сериализует объекты в JSON возвращая обычную строку (string) с текстом в формате JSON. При этом совершенно не требуется обозначать сериализуемый объект или его члены специальными атрибутами.
Конструктор класса JavaScriptSerializer не требует передачи каких либо параметров, а для выполнения сериализации объект передаётся в качестве единственного параметра методу Serialize.
1 2 |
JavaScriptSerializer serializer = new JavaScriptSerializer(); string json = serializer.Serialize(company); |
Десериализация из JSON
Данные сериализованные в JSON можно получить обратно.
Использование класса DataContractJsonSerializer
Десериализация производится при помощи метода ReadObject. В качестве единственного параметра ему передаётся поток с текстом в формате JSON или объект XmlReader для чтения XML сопоставимого с JSON.
При десериализации из потока необходимо установить указатель на позицию соответствующую началу данных в формате JSON (в простейшем случае это 0)..
1 2 |
stream.Position = 0; Company company = (Company)serializer.ReadObject(stream); |
Если требуется десериализовать данные их XML сопоставимого с JSON, создаём XmlReader для этого XML (в данном примере XML хранится в файле) и передаём его в метод ReadObject класса DataContractJsonSerializer.
1 2 |
XmlReader reader = new XmlTextReader("test.xml"); Company company = (Company)serializer.ReadObject(reader); |
Использование класса JavaScriptSerializer
Для десериализации у класса JavaScriptSerializer есть два метода:
- Deserialize.
Обобщённый метод. Десериализует строку в формате JSON в заданный .NET объект; - DeserializeObject.
Десериализует строку в формате JSON в словарь в формате Dictionary <string, object>.
Пример использования метода Deserialize:
1 |
Company company = serializer.Deserialize<Company>(json); |
Пример использования метода DeserializeObject:
1 |
Dictionary<string,object> company = (Dictionary < string,object>) serializer.DeserializeObject(json); |
Метод Deserialize выполняет простую десериализацию, восстанавливая из JSON исходный объект. Метод DeserializeObject возвращает коллекцию, структура которой соответствует структуре исходного JSON. Что даёт возможность работать с JSON как с обычной коллекцией C# извлекая из неё для последующей обработки лишь необходимые данные.
1 |
string Adress = company["Adress"].ToString(); |
Таким образом, в зависимости от требований задачи, можно выбрать наиболее подходящее средство для работы с JSON.
Добрый день.
Спасибо за статью. Кратко и понятно.
На тривиальных объектах все работает.
Но как сериализовавывать коллекции, массивы, IDictionary коллекции и коллекции содержащие экземпляры классов наследников?
Добрый день.
Принцип, что показан в статье является общим для любых объектов. Те же массив или коллекцию можно также обозначить атрибутом [DataMember] и при сериализации они будут сконвертированы в JSON.
Другое дело словари. Но и здесь есть сравнительно простое решение:
serializer.Serialize(keys.ToDictionary(item => item.Key.ToString(), item => item.Value.ToString()));
С коллекциями, которые содержат экземпляры классов наследников всё значительно сложнее.
В общем случае такие коллекции объявляются с указанием базового класса, который не редко является ещё и абстрактным. Поэтому здесь лучше исходить из конкретной задачи.
Добрый день.
Хочу использовать JSon для сохранения настроек формы (Размер, Положение, Видимые колонки в гриде) в компактном читаемом виде.
Провожу эксеперементы с JavaScriptSerializer.
—
По поводу коллекий вроде разобрался.
Этот класс автоматически поддерживает коллекции и Dictionary без всяких дополнительных настроек (В отличии от XmlSerializer).
—
По поводу коллекий, содержащих классы наследники тоже понятно.
Есть специальный конструктор.
new JavaScriptSerializer(new SimpleTypeResolver());
При таком создании JavaScriptSerializer сохраняет вместе с объектом и его тип в тэге __type.
{
"__type": "EhLib.FormSerializator, EhLibControlLibrary, Version=0.98.19.0, Culture=neutral, PublicKeyToken=null",
"Location": {
"__type": "System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"IsEmpty": false,
"X": 78,
"Y": 78
},
...
При десериализации тэг использутся для определения создаваемого типа.
—
Остался вопрос, по определению в run-time какие свойства класса сохранять.
У меня не работают методы ShouldSerialize[Имя свойства]() для указания того нужно ли сохранять свойство.
Подскажите, JavaScriptSerializer действительно не поддерживает ShouldSerialize?
Если не поддерживает, то как этим управлять?
Насколько мне известно, JavaScriptSerializer на самом деле не дружит с шаблоном ShouldSerialize. Но, к счастью это не единственный способ «отловить» изменение параметра.
Как вариант можно использовать событие OnPropertyChanged.
Сама по себе задача сохранения только изменённых свойств вполне решаема, только в данном случае придётся поработать руками, реализуя собственный механизм.
Вообще, для настроек форм и не только в .NET есть специализированный инструментарий основанный на XML, но это, во-первых, тема для отдельного разговора, во-вторых, насколько это подходит для решаемой Вами задачи (всё-таки механизм работы с настройками «из коробки» хранит XML-файлы в профиле пользователя)…
C механизмом XML уже поработали.
Не устраивает генерация слишком «больших» файлов в которых 95% это описание и только 5% сами данные.
Вот пример файла user.config который содержит информацию только об одной форме всего с одним гридом.
user_xml.config
А вот та же информация сохраненная в виде json.
user_json.config
Ни разу даже не слышал о том, чтобы из-за стандартного механизма работы с настройками падала производительность. К стати, ссылки, которые Вы приводите, из документации к библиотеке компонентов EhLib для Delphi. У Microsoft всё несколько по другому.
В прочем, здесь уже «хозяин — барин». Если такой вариант по тем или иным причинам для Вас более приемлем, вопросов нет.
Приветствую!
Подскажите, как реализовать сериализацию в определенное место в файле json. Есть файл с данной структурой:
{
«Groups»: [
{
«UniqueId»: «…»,
«Title»: «…»,
«Subtitle»: «…»,
«ImagePath»: «…»,
«Description»: «…»,
«Items»: [
{
«UniqueId»: «…»,
«Title»: «…»,
«Subtitle»: «…»,
«ImagePath»: «…»,
«Description»: «…»,
«Time»: «…»,
«Client»: «…»,
«Agent»: «…»,
«DateM»: «…»,
«Revision»: «…»,
«Mashine»: «…»,
«IsNew»: false,
«Tools»: [
{
«Title»: «…»,
«Position»: «…»,
«Insert»: «…»,
«ImagePath»: «…»,
«LF»: «…»,
«Adapter»: «…»,
«VC»: «…»,
«FNFZ»: «….»,
«AP»: «…»,
«RE»: «…»,
«NVF»: «…»,
«DCTDZ»: «…»
},
……
Можно добавлять/редактировать или удалять определенные строки?
К сожалению, сериализовать или десериализовать можно только объект целиком.