Что такое эквивалент 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.

🤔 А знаете ли вы, что...
C# также используется для разработки игр с помощью Unity3D, популярного игрового движка.


1
91
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 можно было использовать для поддержки полиморфной десериализации.


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

    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>()
                                    );