Как десериализовать предмет в разные типы? (Newtonsoft, C#,. NET) - PullRequest
0 голосов
/ 12 апреля 2020

Я получаю сообщение json с полем с именем "item", которое можно десериализовать как класс foo или класс-бар. Как мне реализовать это в C#?

Я предполагаю что-то вроде этого:

public class FooOrBar 
{
     // Only one of the two will get populated.
     public Foo foo { get; set; }
     public Bar bar { get; set; }
     bool is_foo;
}

[JsonProperty("item")]
[JsonConverter(typeof(CustomConverter))]
public FooOrBar Item { get; set; }

Как мне реализовать пользовательский конвертер для такого случая?

есть более простое решение?

1 Ответ

1 голос
/ 12 апреля 2020

Я не уверен, как Foo или Bar определяется в вашем коде, но сейчас давайте предположим, что у вас есть структура JSON, подобная этой:

var json = @"
{
  isFoo: true,
  item: {}
}";

В этом случае Foo или Bar определяется isFoo.

FooOrBar класс может быть субъективным. Я бы не стал определять класс таким образом, но использовал бы полиморфизм:

interface IItem
{
    bool IsFoo { get; }
}

class Foo : IItem
{
    public bool IsFoo => true;
}

class Bar : IItem
{
    public bool IsFoo => false;
}

[JsonConverter(typeof(CustomJsonConverter))]
class MyClass
{
    public IItem Item { get; set; }
}

Я установил CustomJsonConverter на MyClass из-за структуры JSON, которая у меня есть. Мне нужно использовать информацию, доступную в родительском объекте item, чтобы определить Foo или Bar, поэтому я должен установить JsonConverter для декларирующего типа свойства Item. Если вы используете информацию, доступную в свойстве item, вы можете переместить конвертер в свойство Item.

Теперь реализуйте CustomJsonConverter следующим образом:

class CustomJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => true;

    public override object ReadJson(JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    {
        var token = JToken.ReadFrom(reader);
        if (token.Type == JTokenType.Null)
        {
            return null;
        }

        // Create an instance of MyClass, and set property as per "isFoo".
        var obj = new MyClass();        

        if (token["isFoo"].Value<bool>())
        {
            obj.Item = new Foo();
        }
        else
        {
            obj.Item = new Bar();
        }

        // Populate properties
        serializer.Populate(token.CreateReader(), obj);
        return obj;
    }

    public override void WriteJson(JsonWriter writer, object value, 
        JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }
}
...