如何使用带有SubTypes的Json.Net和Xamarin反序列化JSON?

时间:2018-01-23 17:05:12

标签: c# json.net subtype

我试图反序化这个json:

{
  "teaser": [{
              "id": "...",
              "type": "category",
              "url": "https:...",
            },{
              "id": "...",
              "type": "brand",
              "url": "https:...",
              "videoCount": 1,
            },{
              "id": "...",
              "type": "video",
              "url": "https:...",
              "headline": "...",
            }]
}

它有一个预告片列表,每个预告片根据其类型而有所不同。 这些将是我的对象:

public class StartPage
{
        public IList<Teaser> Teaser { get; set; }
}

public abstract class Teaser
{
        public string Id { get; set; }
        public string Url { get; set; }
}

public class Video : Teaser
{
        public string Headline { get; set; }
}

public class Brand : Teaser
{
        public int VideoCount { get; set; }
}

我是Json.NET和Xamarin的新手,但还没有为这个案例找到解决方案。之前,当我使用Android Studio和Gson时,我可以通过以下方式注册sybtypes:

RuntimeTypeAdapterFactory<Teaser> teaserRuntimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(
                Teaser.class, "type")
                .registerSubtype(Video.class, Teaser.TYPE_VIDEO)
                .registerSubtype(Brand.class, Teaser.TYPE_BRAND)
                .registerSubtype(Category.class, Teaser.TYPE_CATEGORY);

        return new GsonBuilder()
                .registerTypeAdapterFactory(teaserRuntimeTypeAdapterFactory);

有没有类似的方法来实现我想要的Json.NET,我忽略了什么?

1 个答案:

答案 0 :(得分:0)

您可以做的是在代码段下方创建自定义JsonConverter并找到this点网小提琴

string json ="{ 'Teaser': [{ 'id': '...', 'type': 'category', 'url': 'https:...', },{ 'id': '...', 'type': 'brand', 'url': 'https:...', 'videoCount': 1, },{ 'id': '...', 'type': 'video', 'url': 'https:...', 'headline': '...', }]}";

var list = JsonConvert.DeserializeObject<StartPage>(json);

public class BaseSpecifiedConcreteClassConverter : DefaultContractResolver
    {
        protected override JsonConverter ResolveContractConverter(Type objectType)
        {
            if (typeof(Teaser).IsAssignableFrom(objectType) && !objectType.IsAbstract)
                return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow)
            return base.ResolveContractConverter(objectType);
        }
    }

public class BaseConverter : JsonConverter
    {
        static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new BaseSpecifiedConcreteClassConverter() };

        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(Teaser));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jo = JObject.Load(reader);
            switch (jo["type"].Value<string>())
            {
                case "video":
                    return JsonConvert.DeserializeObject<Video>(jo.ToString(), SpecifiedSubclassConversion);
                case "brand":
                    return JsonConvert.DeserializeObject<Brand>(jo.ToString(), SpecifiedSubclassConversion);
                default:
                    throw new Exception();
            }
            throw new NotImplementedException();
        }

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

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException(); // won't be called because CanWrite returns false
        }
    }

随意在switch case硬代码类名称中创建自定义逻辑可能不是一个好主意,而是创建enum或类似的东西,但这就是你如何实现这种类型的场景