Что такое эквивалент System.Text.Json для XmlElment (имя, тип)

У меня есть следующий класс.

public class Foo
{
    [XmlElement("Bar", typeof(Bar))]
    [XmlElement("Pub", typeof(Pub))]
    public BaseBar Bar { get; set; }
}

Я хотел бы перейти от сериализации XML к сериализации JSON (System.Text.Json), что эквивалентно атрибуту [XmlElement("Bar", typeof(Bar))]?

Смотрите этот образец: https://dotnetfiddle.net/pU8QAU

Редактировать:

Я ищу способ определить его на уровне свойств, поэтому, если у меня есть 2 свойства, я хотел бы иметь для них разные имена.

public class Foo
{
    [XmlElement("Bar", typeof(Bar))]
    [XmlElement("Pub", typeof(Pub))]
    public BaseBar Bar { get; set; }

    [XmlElement("Bar2", typeof(Bar))]
    [XmlElement("Pub2", typeof(Pub))]
    public BaseBar Bar2 { get; set; }
}

Смотрите этот образец: https://dotnetfiddle.net/M6nla

Редактировать2:

Данный ответ Гуру Строна дает этот результат

{"Bar":{"$type":"Pub" …

Я ищу

{"Pub":{…

Где Pub должно быть сериализовано из свойства Bar, если оно имеет тип Pub.

Я не думаю, что есть аналогичный атрибут, но вы можете выбрать пользовательский сериализатор или у вас могут быть оба свойства и третье, которое будет базовым типом и вернет первое ненулевое значение из них (и установщик вы установили одно из них на основе тип)

Selvin 13.02.2023 22:46
...вот так...
Selvin 14.02.2023 13:32
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
Уроки CSS 6
Уроки CSS 6
Здравствуйте дорогие читатели, я Ферди Сефа Дюзгюн, сегодня мы продолжим с вами уроки css. Сегодня мы снова продолжим с так называемых классов.
Что такое Css? Для чего он используется?
Что такое Css? Для чего он используется?
CSS, или "Каскадные таблицы стилей", - это язык стилей, используемый в веб-страницах. CSS является одним из основных инструментов веб-разработки...
1
2
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

.NET 7 и последняя версия System.Text.Json представили поддержку полиморфной сериализации json. Один из способов справиться с этим — использовать JsonDerivedTypeAttribute для базового типа, указав всех потомков:

[JsonDerivedType(typeof(Bar), typeDiscriminator: nameof(Bar))]
[JsonDerivedType(typeof(Pub), typeDiscriminator: nameof(Pub))]
public abstract class BaseBar
{
    public abstract string Text { get; set; }
}

public class Bar : BaseBar
{
    public override string Text { get; set; } = "I am a Bar";
}

public class Pub : BaseBar
{
    public override string Text { get; set; } = "I am a Pub";
}

Пользовательский преобразователь предыдущей версии .NET 7 можно было использовать для поддержки полиморфной десериализации.

Вы могли заставить полиморфную десериализацию работать до .NET 7, но это было не для слабонервных.

Flydog57 13.02.2023 22:23

Поэтому я не могу указать это на уровне свойства, например. если бы у меня было два свойства с одним и тем же классом и оба с разными именами?

Rand Random 13.02.2023 22:38

В качестве примера вы можете увидеть это: dotnetfiddle.net/M6nlaV

Rand Random 13.02.2023 22:42

Еще раз посмотрел на вывод json вашего примера и возник еще один вопрос. Я бы предпочел, чтобы само имя свойства изменилось, чтобы отразить тип, поэтому вместо {"Bar":{"$type":"Pub" … я бы предпочел {"Pub":{…

Rand Random 13.02.2023 22:54

@RandRandom это не то, как работает стандартная сериализация json, но вы можете написать свой собственный сериализатор. Это будет работать до тех пор, пока у вас не будет двух свойств одного и того же базового типа с одним и тем же фактическим типом значения (рекомендуется, чтобы ваши ключи в json были уникальными).

Guru Stron 13.02.2023 22:57

Чтобы сериализовать ваши данные, вам даже не нужен атрибут имени элемента, если у вас такое же имя свойства и вам не нужен корневой класс, вы можете использовать словарь

    var foo = new Dictionary<string, BaseBar> {
                           { "Bar", new Bar() },
                           { "Pub", new Pub() }
                           };

    var json = System.Text.Json.JsonSerializer.Serialize(foo, 
                                new JsonSerializerOptions{WriteIndented = true}
                                );

Выход

{
  "Bar": {
    "Text": "I am a Bar"
  },
  "Pub": {
    "Text": "I am a Pub"
  }
}

Десериализовать

Dictionary<string, BaseBar> foo = JsonObject.Parse(json).AsObject()
                                    .ToDictionary(p => p.Key, p => p.Key == "Bar" ? 
                                      (BaseBar)p.Value.Deserialize<Bar>()
                                    : (BaseBar)p.Value.Deserialize<Pub>()
                                    );

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