JSON.NET:如何反序列化基础上的父(持有人)对象的值接口的财产? [英] JSON.NET: How to deserialize interface property based on parent (holder) object value?

查看:137
本文介绍了JSON.NET:如何反序列化基础上的父(持有人)对象的值接口的财产?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的类

class Holder {
    public int ObjType { get; set; }
    public List<Base> Objects { get; set; }
}

abstract class Base {
    // ... doesn't matter
}

class DerivedType1 : Base {
    // ... doesn't matter
}

class DerivedType2 : Base {
    // ... doesn't matter
}

使用的WebAPI我想接收对象并正确反序列化。根据 OBJTYPE 价值,我需要对象来进行反序列化财产无论是作为列表&LT; D​​erivedType1&GT; OBJTYPE == 1 )或列表&LT; D​​erivedType2&GT; OBJTYPE == 2 )。

Using WebAPI I want to receive the object Holder and deserialize it correctly. Based on the ObjType value I need Objects property to be deserialized either as List<DerivedType1> (ObjType == 1) or List<DerivedType2> (ObjType == 2).

目前,我中搜寻和互联网的最好的方法,但我发现最好的是这个答案的http://计算器.COM / A /1038496分之8031283。这种解决方案的问题在于,它的父对象的宽松环境,所以我无法找到 OBJTYPE 的价值。 OK,我可以创建自定义的 JsonConverter 和remebering的 OBJTYPE 价值,但我依然affraid这行

At the moment I searched SO and internet for best approach, but the best I've found is this answer http://stackoverflow.com/a/8031283/1038496. The problem of this solution is, that it loose context of parent object, so I cannot find out the value of ObjType. OK, I could solve it by creating custom JsonConverter for Holder and remebering the ObjType value, but still I'm affraid of this line

serializer.Populate(jObject.CreateReader(), target);

因为这个答案下面的评论说:

as the comment below this answer says

在ReadJson方法创建的新JsonReader不继承任何原始读者的配置值(文化,DateParseHandling,DateTimeZoneHandling,FloatParseHandling等)的。这些值应使用serializer.Populate()新JsonReader之前被复制。

The new JsonReader created in the ReadJson method does not inherit any of the original reader's configuration values (Culture, DateParseHandling, DateTimeZoneHandling, FloatParseHandling, etc...). These values should be copied over before using the new JsonReader in serializer.Populate().

这是我的问题,我自己复制这些值似乎并不干净,我(如果我错过了什么?)

which is problem for me and copying these values by myself doesn't seem clean to me (what if I miss something?)

所以,问题是:有没有更好的方法我已经错过了基于parent属性值进行反序列化抽象的对象属性

推荐答案

您是在正确的轨道上。你需要实现一个自定义的 JsonConverter 类来处理这种情况下,如你所说。但是,不要担心,这是可以编写转换器以这样一种方式,你可以使用传递到转换器的原始阅读器和串行情况下,从来没有需要到设置在复制到新的实例。下面是我会怎么写:

You are on the right track. You do need to implement a custom JsonConverter for your Holder class to handle this situation, as you suggested. But, don't worry, it is possible to write the converter in such a way that you can use the original reader and serializer instances passed to the converter, without ever needing to copy the settings over to new instances. Here is how I would write it:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        Holder holder = new Holder();
        holder.ObjType = (int)jo["ObjType"];
        holder.Objects = new List<Base>();
        foreach (JObject obj in jo["Objects"])
        {
            if (holder.ObjType == 1)
                holder.Objects.Add(obj.ToObject<DerivedType1>(serializer));
            else
                holder.Objects.Add(obj.ToObject<DerivedType2>(serializer));
        }
        return holder;
    }

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

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

下面是一个快速演示:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        [
            {
                ""ObjType"" : 1,
                ""Objects"" : 
                [
                    { ""Id"" : 1, ""Foo"" : ""One"" },
                    { ""Id"" : 2, ""Foo"" : ""Two"" },
                ]
            },
            {
                ""ObjType"" : 2,
                ""Objects"" : 
                [
                    { ""Id"" : 3, ""Bar"" : ""Three"" },
                    { ""Id"" : 4, ""Bar"" : ""Four"" },
                ]
            },
        ]";

        List<Holder> list = JsonConvert.DeserializeObject<List<Holder>>(json);

        foreach (Holder holder in list)
        {
            if (holder.ObjType == 1)
            {
                foreach (DerivedType1 obj in holder.Objects)
                {
                    Console.WriteLine("Id: " + obj.Id + "  Foo: " + obj.Foo);
                }
            }
            else
            {
                foreach (DerivedType2 obj in holder.Objects)
                {
                    Console.WriteLine("Id: " + obj.Id + "  Bar: " + obj.Bar);
                }
            }
        }
    }
}

[JsonConverter(typeof(HolderConverter))]
class Holder
{
    public int ObjType { get; set; }
    public List<Base> Objects { get; set; }
}

abstract class Base
{
    public int Id { get; set; }
}

class DerivedType1 : Base
{
    public string Foo { get; set; }
}

class DerivedType2 : Base
{
    public string Bar { get; set; }
}

输出:

Id: 1  Foo: One
Id: 2  Foo: Two
Id: 3  Bar: Three
Id: 4  Bar: Four

这篇关于JSON.NET:如何反序列化基础上的父(持有人)对象的值接口的财产?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆