使用抽象属性JSON

时间:2016-03-20 16:37:12

标签: json json.net json-deserialization

public abstract class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [JsonProperty(Required = Required.Always)]
        public string Type { get; set; }
    }

    public class Employee : Person
    {
        public string Department { get; set; }
        public string JobTitle { get; set; }
    }

    public class Artist : Person
    {
        public string Skill { get; set; }
    }

我已经有一个JSON转换器正在根据Type属性的值对这些对象进行反序列化。

public abstract class JsonCreationConverter<T> : JsonConverter
    {
        protected abstract T Create(Type objectType, JObject jObject);

        public override bool CanConvert(Type objectType)
        {
            Type t = typeof(T);
            return typeof(T).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jObject = JObject.Load(reader);
            T target = Create(objectType, jObject);
            serializer.Populate(jObject.CreateReader(), target);
            return target;
        }

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

    public class PersonConverter : JsonCreationConverter<Person>
    {
        protected override Person Create(Type objectType, JObject jObject)
        {
            if(jObject["Type"] == null)
            {
                throw new ArgumentException();
            }

            string type = (string)jObject["Type"];
            if(type == null)
            {
                throw new ArgumentException();
            }

            if(type.Equals("Employee", StringComparison.InvariantCultureIgnoreCase))
            {
                return new Employee();
            }
            else if (type.Equals("Artist", StringComparison.InvariantCultureIgnoreCase))
            {
                return new Artist();
            }

            return null;
        }
    }

string json = "[{\"Department\": \"Department1\",\"JobTitle\": \"JobTitle1\",\"FirstName\": \"FirstName1\",\"LastName\": \"LastName1\",\"Type\": \"Employee\"},{\"Skill\": \"Drawer\",\"FirstName\": \"FirstName1\",\"LastName\": \"LastName1\",\"Type\": \"Artist\"}]";
List<Person> person = JsonConvert.DeserializeObject<List<Person>>(json, new PersonConverter());

上述效果很好。

现在,我是以下课程:

public class City
    {
        public string Name { get; set; }
        public int Population { get; set; }
        public Person[] Persons { get; set; }
    }

如何为这个可以使用Person类Converter初始化Persons属性的City类编写转换器?我最初的想法是将Persons部分提取为JObject,然后使用PersonConverter在其上调用Deserialize,类似于下面的ReadJson方法。

 var p = jObject["Persons"].ToString();
 List<Person> persons = JsonConvert.DeserializeObject<List<Person>>(p, new PersonConverter());

但是ReadJson在serializer.Populate方法中抛出异常,因为抽象类无法实例化。

有什么想法吗?以下是json字符串作为示例

string Cityjson = "{\"Name\": \"London\" , \"Population\": \"1000\" , \"Persons\": [{\"Department\": \"Department1\",\"JobTitle\": \"JobTitle1\",\"FirstName\": \"FirstName1\",\"LastName\": \"LastName1\",\"Type\": \"Employee\"},{\"Skill\": \"Drawer\",\"FirstName\": \"FirstName1\",\"LastName\": \"LastName1\",\"Type\": \"Artist\"}]}";

方法#1

我通过

解决了这个问题

1)在反序列化中标记人员属性

[JsonIgnore]
public Person[] Persons { get; set; }

2)在Create方法中实例化City对象并使用Person转换器初始化Persons属性

protected override City Create(Type objectType, JObject jObject)
        {
            if (jObject["Persons"] == null)
            {
                throw new ArgumentException();
            }

            var p = jObject["Persons"].ToString();

            List<Person> persons = JsonConvert.DeserializeObject<List<Person>>(p, new PersonConverter());
            var city = new City();
            city.Persons = persons.ToArray();
            return city;
        }

ReadJson方法会像往常一样填充剩余的城市房产

还有其他方法吗?

1 个答案:

答案 0 :(得分:0)

我认为这是最合适的方式

在ReadJson中传递数组时它基本上崩溃了,因为Jarray不是jboject。所以,我更新了ReadJson,如下所示,它有效。

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                JArray jObject = JArray.Load(reader);
                List<T> list = new List<T>();
                for (int i = 0; i < jObject.Count(); i++)
                {
                    var p = jObject[i];
                    JObject ob = p as JObject;
                    T value = Create(objectType, ob);
                    serializer.Populate(ob.CreateReader(), value);
                    list.Add(value);
                }

                return list.ToArray();
            }
            else
            {
                JObject jObject = JObject.Load(reader);
                T target = Create(objectType, jObject);
                serializer.Populate(jObject.CreateReader(), target);
                return target;
            }
        }

是的,我不需要CityConverter。添加PersonConverter就足够了。