使用抽象属性 JSON 反序列化类


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; }
    }

如何为此 City 类编写可以使用 PersonConverter 初始化 Person 属性的转换器?我最初的想法是将 Person 部分提取为 JObject,然后在其 ReadJson 方法中使用 PersonConverter 对其调用反序列化,类似于下面的示例。

 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. 将 Person 属性标记为在反序列化中忽略

    [Json忽略]公共人员[] 人员 { get; set; }

  2. 在 Create 方法中,实例化 City 对象并使用 PersonConverter 初始化 Person 属性

    受保护的覆盖 City Create(Type objectType, JObject jObject){if (jObject["Persons"] == null){抛出新的 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 方法将像往常一样填充其余的 City 属性。

还有其他方法吗?

我认为这是最合适的方式

在 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就足够了。

相关内容

  • 没有找到相关文章

最新更新