使用 JSON.NET 使用 IEnumerable 反序列化对象
Deserialize an object with an IEnumerable using JSON.NET
考虑以下 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 转换器反序列化可能是 Toaster
或 Kettle
的 IEnumerable。这里的想法是,一旦我通过查看 json 知道 ApplianceType 是什么,我就可以 return 一个具体类型。我一直在关注 this Whosebug post 尝试让它工作,但没有成功。
这是转换器代码:
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);
in the JsonCreationConverter
Newtonsoft.Json.JsonReaderException: 'Error reading JObject from
JsonReader. Current JsonReader item is not an object: StartArray. Path
'Appliances'
我猜它正在进入 IEnumerable 并且只是失败了,我在这里做错了什么?
注释这行代码
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());
考虑以下 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 转换器反序列化可能是 Toaster
或 Kettle
的 IEnumerable。这里的想法是,一旦我通过查看 json 知道 ApplianceType 是什么,我就可以 return 一个具体类型。我一直在关注 this Whosebug post 尝试让它工作,但没有成功。
这是转换器代码:
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);
in the JsonCreationConverter
Newtonsoft.Json.JsonReaderException: 'Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path 'Appliances'
我猜它正在进入 IEnumerable 并且只是失败了,我在这里做错了什么?
注释这行代码
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());