考虑以下json和模型:
{
"Reference": "Bay House 22",
"Appliances": [
{
"Reference": "Kitchen Appliance 1",
"ApplianceType": "0",
"NumberOfSlots": 4
},
{
"Reference": "Kitchen Appliance 2",
"ApplianceType": "1",
"Capacity": 1500
}
]
}
public class HouseModel
{
public String Reference { get; set; }
[JsonConverter(typeof(ApplianceModelConverter))]
public IEnumerable<IApplianceModel> Appliances { get; set; }
}
public interface IApplianceModel
{
String Reference { get; set; }
ApplianceType ApplianceType { get; set; } // this is an enum
}
public class ToasterModel : IApplianceModel
{
public String Reference { get; set; }
public ApplianceType ApplianceType { get; set; }
public Int32 NumberOfSlots { get; set; }
}
public class KettleModel : IApplianceModel
{
public String Reference { get; set; }
public ApplianceType ApplianceType { get; set; }
public Int32 Capacity { get; set; }
}
我正在尝试使用自定义json转换器反序列化IEnumerable,该IEnumerable可以是Toaster
或Kettle
。这里的想法是,一旦我了解了ApplianceType,就可以通过查看json返回具体类型。我一直在关注this stackoverflow帖子,尝试使其正常运行,但没有成功。
这是转换器代码:
public abstract class JsonCreationConverter<T> : JsonConverter
{
protected abstract T Create(Type objectType, JObject jObject);
public override Boolean CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override Boolean CanWrite
{
get { return false; }
}
public override Object ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
public class ApplianceModelConverter: JsonCreationConverter<IApplianceModel>
{
protected override IApplianceModel Create(Type objectType, JObject jObject)
{
if (jObject["applianceType "] == null)
{
throw new ArgumentException("Missing ApplianceType");
}
ApplianceType applianceType = jObject.Value<ApplianceType>();
switch (applianceType )
{
case ApplianceType.Kettle:
return new KettleModel();
case ApplianceType.Toaster:
return new ToasterModel();
default:
throw new InvalidEnumArgumentException("ApplianceType not supported");
}
}
}
当前执行此行时引发异常:JObject jObject = JObject.Load(reader);
中的JsonCreationConverter
Newtonsoft.Json.JsonReaderException:'从中读取JObject时出错 JsonReader。当前JsonReader项不是对象:StartArray。路径 “家电”
我想它已经到IEnumerable了,只是失败了,我在这里做什么错了?
答案 0 :(得分:2)
注释此行代码
public class HouseModel
{
public String Reference { get; set; }
//[JsonConverter(typeof(ApplianceModelConverter))] //=> You don't need this
public IEnumerable<IApplianceModel> Appliances { get; set; }
}
也将Create方法更改为此
protected override IApplianceModel Create(Type objectType, JObject jObject)
{
if (jObject["ApplianceType"] == null) //case sensitive
{
throw new ArgumentException("Missing ApplianceType");
}
//ApplianceType applianceType = jObject.Value<ApplianceType>(); //this might throw invalid cast exception
ApplianceType applianceType = jObject["ApplianceType"].ToObject<ApplianceType>();
switch (applianceType)
{
case ApplianceType.Kettle:
return new KettleModel();
case ApplianceType.Toaster:
return new ToasterModel();
default:
throw new InvalidEnumArgumentException("ApplianceType not supported");
}
}
如果我们正在使用此方法反序列化
string json = "{\"Reference\": \"Bay House 22\",\"Appliances\": [{\"Reference\": \"Kitchen Appliance 1\",\"ApplianceType\": \"0\",\"NumberOfSlots\": 4},{\"Reference\": \"Kitchen Appliance 2\",\"ApplianceType\": \"1\",\"Capacity\": 1500}]}";
HouseModel houseModels = JsonConvert.DeserializeObject<HouseModel>(json, new ApplianceModelConverter());