C#: конструктор копирования или конструктор-десериализатор из JSON
По условию задачи мне надо десериализовать объект из JSON:
- Есть класс, в нём много свойств. Можно на первом этапе считать, что все свойства - «невложенные», то есть что-то вроде такого:
public class ContragentPayment
{
public int Id { get; set; }
public int Status { get; set; }
public int ArticleId { get; set; }
public DateTime PaymentDate { get; set; }
public int? InvoiceId { get; set; }
public decimal Price { get; set; }
public int CurrencyId { get; set; }
public decimal CurrencyRate { get; set; }
public int? OrderId { get; set; }
public string PaySubject { get; set; }
}
С сервера приходит сериализованный в JSON объект идентичной структуры (то есть, с теми же свойствами). При этом на клиенте я могу переписать класс как угодно, главное, чтобы тот же набор свойств можно было отобразить на клиенте.
Мне было бы очень удобно этот JSON передавать в конструктор, чтобы писать что-то вроде
ContragentPayment cp = new ContragentPayment(cp_as_json_string);
Подключил пакет System.Text.Json, десериализую JSON так:
var tmp = JsonSerializer.Deserialize<ContragentPayment>(cp_as_json_string);
Но я не могу понять, как поместить эту строку кода в конструктор, ведь thisдоступен только для чтения, то есть я не могу написать:
var tmp = new ContragentPayment(cp_as_json_string);
this = tmp;`
Вот если бы у меня в классе ContragentPayment был конструктор копирования, чтобы я мог инициализировать экземпляр объекта другим экземпляром объекта.
Я смотрю пример, и вижу, что в примере конструктора копирования используется перебор всех свойств вручную, мне же не хотелось бы этого делать, так как их достаточно много. То есть мне нужно либо что-то вроде AutoMapper, либо придётся «наступить на свою гордость» и написать блок кода, который сделает это через Reflection: переберёт свойства, но сделает это автоматически.
Однако, AutoMapper -- это лишняя внешняя зависимость, да и вообще -- стрельба из пушки по воробьям, а перебор через Reflection мне кажется вычурным и не соответствующим простоте задачи.
Возможно, я упускаю какую то очень простую вещь, на уровне базового синтаксиса языка, которая позволяет выкрутиться? Не посоветуете ли, в какую сторону копать?
Спасибо большое!
Ответы (1 шт):
Для того, чтобы заполнить объект данными из JSON, можно использовать JsonConvert.PopulateObject, если вы перейдёте на более старый Newtonsoft JSON.NET:
public ContragentPayment(string jsonSource)
{
JsonConvert.PopulateObject(jsonSource, this);
}
Подобной функциональности пока нету в System.Text.Json, хотя существуют различные обходные пути.
Но, как верно отмечено в комментариях, конструктор десериализации — это не самая лучшая идея: класс по идее не должен заниматься десериализацией самого себя.
Я бы посоветовал просто использовать JsonSerializer.Deserialize<ContragentPayment>(json) вместо конструктора.
Для реализации копирования проще всего использовать record. В record и так объявлен клонирующий конструктор, но он объявлен как protected, и используется в конструкции with. Можно выставить это наружу:
public ContragentPayment CreateCopy() => this with { };
Внимание: при этом вы получите shallow copy, то есть, другой объект, у которого будут скопированы (но не склонированы!) все свойства. Впрочем, если ваши DTO-классы будут неизменяемыми (immutable), то разницы особой и нет.