使用摘要 属性 JSON 反序列化 class
Deserializing class with abstract property 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 转换器根据类型 属性 的值反序列化此类对象。
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());
上面的效果很好。
现在,我有以下 class:
public class City
{
public string Name { get; set; }
public int Population { get; set; }
public Person[] Persons { get; set; }
}
如何为这个城市 class 编写一个可以使用 PersonConverter 来初始化 Persons 属性 的转换器?我最初的想法是将 Persons 部分提取为 JObject,然后在其 ReadJson 方法中使用 PersonConverter 对其调用反序列化,类似于下面的示例。
var p = jObject["Persons"].ToString();
List<Person> persons = JsonConvert.DeserializeObject<List<Person>>(p, new PersonConverter());
但是 ReadJson 在 Serializer.Populate 方法中抛出异常,因为抽象 classes 无法实例化。
以下以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
我通过
解决了这个问题
标记要在反序列化中忽略的人 属性
[JsonIgnore]
public 人[] 人 { get;放; }
Create方法中,实例化City对象,使用PersonConverter初始化Persons属性
受保护的重写 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 就足够了。
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 转换器根据类型 属性 的值反序列化此类对象。
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());
上面的效果很好。
现在,我有以下 class:
public class City
{
public string Name { get; set; }
public int Population { get; set; }
public Person[] Persons { get; set; }
}
如何为这个城市 class 编写一个可以使用 PersonConverter 来初始化 Persons 属性 的转换器?我最初的想法是将 Persons 部分提取为 JObject,然后在其 ReadJson 方法中使用 PersonConverter 对其调用反序列化,类似于下面的示例。
var p = jObject["Persons"].ToString();
List<Person> persons = JsonConvert.DeserializeObject<List<Person>>(p, new PersonConverter());
但是 ReadJson 在 Serializer.Populate 方法中抛出异常,因为抽象 classes 无法实例化。
以下以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
我通过
解决了这个问题标记要在反序列化中忽略的人 属性
[JsonIgnore] public 人[] 人 { get;放; }
Create方法中,实例化City对象,使用PersonConverter初始化Persons属性
受保护的重写 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 就足够了。