Как добавить JsonPropertyName к унаследованным свойствам?

Как мне десериализовать json в мой класс, который наследуется от базового класса, но свойства в базовом классе не соответствуют json? Я не могу управлять базовым классом. Например:

{
  "prop1": "Value1",
  "prop2": "Value2"
}

Я хочу десериализовать выше в MyClass:

public class MyClass : Base
{
    [JsonPropertyName("prop2")]
    public string? Property2 { get; set; }
}

public class Base // I do not own this
{
  public string? Property1 { get; init; }
}

Должен ли я переопределять базовые свойства и украшать их?

У вас есть контроль над базовым классом? Вы можете внести в это изменения?

DavidG 13.02.2023 12:41

@Pawel, ваш код не может быть скомпилирован по событию. Пожалуйста, опубликуйте правильный

Serge 13.02.2023 12:53

@Павел {получить; в этом; } "{get;init;}" как это инициализируется?

Serge 13.02.2023 13:11

@Серж, я не понимаю, что ты имеешь в виду. Property1 доступен только для инициализации.

Pawel 13.02.2023 13:22

@Pawel Да, но где код для его инициализации? У него есть специальный конструктор?

Serge 13.02.2023 13:42

Вам нужно сериализовать или только десериализовать?

dbc 13.02.2023 16:22

@Serge Без явного конструктора я бы предположил, что свойства только для инициализации могут быть инициализированы только с помощью инициализаторов объектов. Например MyClass a = new() { Property1 = "v1" };

Pawel 13.02.2023 17:53

@dbc Только десериализация.

Pawel 13.02.2023 17:53
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
БЭМ: Конвенция об именовании CSS
БЭМ: Конвенция об именовании CSS
Я часто вижу беспорядочный код CSS, особенно если проект большой. Кроме того, я совершал эту ошибку в профессиональных или личных проектах и...
Революционная веб-разработка ServiceNow
Революционная веб-разработка ServiceNow
В быстро развивающемся мире веб-разработки ServiceNow для достижения успеха крайне важно оставаться на вершине последних тенденций и технологий. По...
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Заголовок веб-страницы играет наиболее важную роль в SEO, он помогает поисковой системе понять, о чем ваш сайт.
Конфигурация Jest в angular
Конфигурация Jest в angular
В этой статье я рассказываю обо всех необходимых шагах, которые нужно выполнить при настройке jest в angular.
0
8
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы хотите использовать то же имя свойства, вам следует скрыть свойство базового класса с помощью ключевого слова new и пометить его атрибутом JsonPropertyName:

public class MyClass : Base
{
    [JsonPropertyName("prop2")]
    public string? MyProperty2 { get; set; }

    [JsonPropertyName("prop1")]
    public new string? Property1 { get; set; }
}

Также вы можете реализовать JsonConverter для типа вместо того, чтобы находить определенные свойства в JSON и сопоставлять их со свойствами объекта. Это защитит вашу модель от конкретной модели JSON.

public class MyClassJsonConverter : JsonConverter<MyClass>
{
    public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var jsonDocument = JsonDocument.ParseValue(ref reader);
        var rootElement = jsonDocument.RootElement;
        var myClass = new MyClass();
        myClass.Property1 = rootElement.GetProperty("prop1").GetString();
        myClass.Property2 = rootElement.GetProperty("prop2").GetString();
        return myClass;
    }

    public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options)
    {
        // imlement logic here if needed
        throw new NotImplementedException();
    }
}

[JsonConverter(typeof(MyClassJsonConverter))]
public class MyClass : Base
{
    public string? MyProperty2 { get; set; }
}

Также здесь есть большая подробная статья "Как написать собственные конвертеры для сериализации JSON (marshalling) в .NET" с примерами конвертеров, фабрикой конвертеров, регистрацией конвертеров обработки ошибок и другими аспектами конвертеров для сериализации JSON.

Например, вам не нужно использовать JsonConverterAttribute и вызывать Deserialize с явно указанными преобразователями:

public class MyClass : Base
{
    public string? MyProperty2 { get; set; }
}

var serializeOptions = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters =
    {
        new MyClassJsonConverter()
    }
};

var myClass = JsonSerializer.Deserialize<MyClass>(jsonString, deserializeOptions)!;

"с новым ключевым словом и отметить атрибутом JsonPropertyName:" - но лучше этого не делать =)

Guru Stron 13.02.2023 12:45

@GuruStron Да, я согласен с тем, что это плохая практика, а также в целом модель должна быть независимой от формата хранения. Тогда есть лучшее и сложное решение с JsonConverter :)

Vadim Martynov 13.02.2023 12:51

Класс не может наследовать от записи

Serge 13.02.2023 13:01

@Серж, я исправил свой вопрос. Спасибо за указание на это.

Pawel 13.02.2023 17:56

@vadim-martynov Спасибо, я обнаружил, что подход «скрыть с ключевым словом new» работает лучше всего в моем случае. Мне пришлось немного изменить реализацию, потому что базовый класс выполнял некоторую логику с Property1 при инициализации, и чтобы базовое значение не было нулевым, я сделал это: [JsonPropertyName("prop1")] public new string? Property1 { get => base.Property1; init => base.Property1 = value; }. Почему вы считаете это плохой практикой?

Pawel 13.02.2023 18:13

Вы можете использовать собственный JsonConverter от @VadimMartynov, но более простой способ — добавить свойство

public class MyClass : Base
{
    [JsonPropertyName("prop2")]
    public string? Property2 { get; set; }

    [JsonPropertyName("prop1")]
    public new string? Property1
    {
        get { return base.Property1; }
        init { base.Property1 = value; }
    }
}

Но я рекомендую вам начать использовать Newtonsoft.Json. Этот код был бы намного понятнее

public class MyClass : Base
{
    [JsonProperty("prop2")]
    public string? Property2 { get; set; }

    [JsonConstructor]
    public MyClass(string? prop1)
    {
        Property1 = prop1;
    }
}

Другие вопросы по теме