Как десериализовать JSON в IEnumerable <BaseType> с помощью Newtonsoft JSON.NET

учитывая этот JSON:

[
  {
    "$id": "1",
    "$type": "MyAssembly.ClassA, MyAssembly",
    "Email": "[email protected]",
  },
  {
    "$id": "2",
    "$type": "MyAssembly.ClassB, MyAssembly",
    "Email": "[email protected]",
  }
]

и эти классы:

public abstract class BaseClass
{
    public string Email;
}
public class ClassA : BaseClass
{
}
public class ClassB : BaseClass
{
}

Как я могу десериализовать JSON в:

IEnumerable<BaseClass> deserialized;

Я не могу использовать JsonConvert.Deserialize<IEnumerable<BaseClass>>(), потому что он жалуется, что BaseClass является абстрактным.

Ответ 1

вам нужно:

 JsonSerializerSettings settings = new JsonSerializerSettings
                 {
                     TypeNameHandling = TypeNameHandling.All
                 };

string strJson = JsonConvert.SerializeObject(instance, settings);

поэтому JSON выглядит так:

{
  "$type": "System.Collections.Generic.List`1[[MyAssembly.BaseClass, MyAssembly]], mscorlib",
  "$values": [
    {
      "$id": "1",
      "$type": "MyAssembly.ClassA, MyAssembly",
      "Email": "[email protected]",
    },
    {
      "$id": "2",
      "$type": "MyAssembly.ClassB, MyAssembly",
      "Email": "[email protected]",
    }
  ]
}

то вы можете десериализировать его:

BaseClass obj = JsonConvert.DeserializeObject<BaseClass>(strJson, settings)

Документация: Настройка TypeNameHandling

Ответ 2

используйте следующую конструкцию JsonSerializerSettings при десериализации:

new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Objects
})

Ответ 3

Вот способ сделать это без заполнения типа $в json.

Конвертер Json:

public class FooConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(BaseFoo));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        if (jo["FooBarBuzz"].Value<string>() == "A")
            return jo.ToObject<AFoo>(serializer);

        if (jo["FooBarBuzz"].Value<string>() == "B")
            return jo.ToObject<BFoo>(serializer);

        return null;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

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

используя его:

var test = JsonConvert.DeserializeObject<List<BaseFoo>>(result, new JsonSerializerSettings() 
{ 
    Converters = { new FooConverter() }
});

взято из здесь

Ответ 4

Вы также можете обернуть перечислимое в класс:

class Wrapper
{
    IEnumerable<BaseClass> classes;
}

затем сериализуем и десериализуем это.