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
我通过以下方式解决了这个问题
将 Person 属性标记为在反序列化中忽略
[Json忽略]公共人员[] 人员 { get; set; }
在 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就足够了。