有条件地将不同的 json 属性 反序列化为同一模型 属性
Deserialize different json property to same model property conditionally
假设我有以下 json。
{
"allitemscount":2,
"allitems":[
{"itemid":"1","itemname":"one"},
{"itemid":"2","itemname":"two"}],
"customitems":[
{"itemid":"3","itemname":"three"},
{"itemid":"4","itemname":"four"}]
}
反序列化这个 json 时,它应该转到下面的 C# 模型。
public class response
{
public int allitemscount;
public List<item> items;
}
public class item
{
public string itemid;
public string itemname;
}
问题:
如何根据条件在 allitems
和 customitems
之间切换?例如,如果 useAllitems
为真,allitems
来自 json 要填写的项目,如果 useCustomItems
为真, customitems
要填写的项目属性。请帮助如何做到这一点。
在 public List<item> items
上使用 JsonProperty 允许在 allitems
之间切换,但是有没有一种方法可以根据上述条件进行反序列化。
您可以通过如下更改 response
class 来反序列化上述 json,
public class response{
public int allitemscount;
public List<item> allitems;
public List<item> customitems;
}
然后使用下面的代码,
var jsonData = "{\"allitemscount\":2, \"allitems\":[{\"itemid\":\"1\",\"itemname\":\"one\"}, {\"itemid\":\"2\",\"itemname\":\"two\"}],\"customitems\":[{\"itemid\":\"3\",\"itemname\":\"three\"},{\"itemid\":\"4\",\"itemname\":\"four\"}]}";
var data = JsonConvert.DeserializeObject<response>(jsonData);
foreach(var str in data.allitems) {
Console.WriteLine(str.itemid +'-'+str.itemname);
}
foreach(var str in data.customitems) {
Console.WriteLine(str.itemid +'-'+str.itemname);
}
我是通过编写我们自己的继承自 JsonConverter 的 ItemConverter 实现的,
我在尝试中使用的示例模型 json:
{
"allitemscount": 2,
"UseCustomItems": true,
"allitems": [
{
"itemid": "1",
"itemname": "one"
},
{
"itemid": "2",
"itemname": "two"
}
],
"customitems": [
{
"itemid": "3",
"itemname": "three"
},
{
"itemid": "4",
"itemname": "four"
}
]
}
控制台应用程序的主要方法:
static void Main(string[] args)
{
using (StreamReader r = new StreamReader(@"\model.json")) // json path
{
string json = r.ReadToEnd();
var deserializedJson = JsonConvert.DeserializeObject<Result>(json, new ItemConverter());
}
}
型号:
public class Result // main object
{
[JsonProperty("allitemscount")]
public long Allitemscount { get; set; }
public bool UseCustomItems { get; set; }
}
public class ResultA : Result // CustomItems Model
{
[JsonProperty("customitems")]
private List<Item> Items { get; set; }
}
public class ResultB : Result // AllItems Model
{
[JsonProperty("allitems")]
private List<Item> Items { get; set; }
}
public class Item
{
[JsonProperty("itemid")]
public string Itemid { get; set; }
[JsonProperty("itemname")]
public string Itemname { get; set; }
}
以及我们在反序列化到对象时使用的 ItemConverter:
internal class ItemConverter : JsonConverter
{
private Type currentType;
public override bool CanConvert(Type objectType)
{
return typeof(Item).IsAssignableFrom(objectType) || objectType == typeof(Result);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
if (item["UseCustomItems"] != null)
{
// save the type for later.
switch (item["UseCustomItems"].Value<bool>())
{
case true:
currentType = typeof(ResultA);
return item.ToObject<ResultA>(); // return result as customitems result
case false:
currentType = typeof(ResultB);
return item.ToObject<ResultB>(); // return result as allitems result
}
return item.ToObject<Result>();
}
// use the last type you read to serialise.
return item.ToObject(currentType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
结果应该如下图所示
希望这个解决方案对您有所帮助
假设我有以下 json。
{
"allitemscount":2,
"allitems":[
{"itemid":"1","itemname":"one"},
{"itemid":"2","itemname":"two"}],
"customitems":[
{"itemid":"3","itemname":"three"},
{"itemid":"4","itemname":"four"}]
}
反序列化这个 json 时,它应该转到下面的 C# 模型。
public class response
{
public int allitemscount;
public List<item> items;
}
public class item
{
public string itemid;
public string itemname;
}
问题:
如何根据条件在 allitems
和 customitems
之间切换?例如,如果 useAllitems
为真,allitems
来自 json 要填写的项目,如果 useCustomItems
为真, customitems
要填写的项目属性。请帮助如何做到这一点。
在 public List<item> items
上使用 JsonProperty 允许在 allitems
之间切换,但是有没有一种方法可以根据上述条件进行反序列化。
您可以通过如下更改 response
class 来反序列化上述 json,
public class response{
public int allitemscount;
public List<item> allitems;
public List<item> customitems;
}
然后使用下面的代码,
var jsonData = "{\"allitemscount\":2, \"allitems\":[{\"itemid\":\"1\",\"itemname\":\"one\"}, {\"itemid\":\"2\",\"itemname\":\"two\"}],\"customitems\":[{\"itemid\":\"3\",\"itemname\":\"three\"},{\"itemid\":\"4\",\"itemname\":\"four\"}]}";
var data = JsonConvert.DeserializeObject<response>(jsonData);
foreach(var str in data.allitems) {
Console.WriteLine(str.itemid +'-'+str.itemname);
}
foreach(var str in data.customitems) {
Console.WriteLine(str.itemid +'-'+str.itemname);
}
我是通过编写我们自己的继承自 JsonConverter 的 ItemConverter 实现的,
我在尝试中使用的示例模型 json:
{
"allitemscount": 2,
"UseCustomItems": true,
"allitems": [
{
"itemid": "1",
"itemname": "one"
},
{
"itemid": "2",
"itemname": "two"
}
],
"customitems": [
{
"itemid": "3",
"itemname": "three"
},
{
"itemid": "4",
"itemname": "four"
}
]
}
控制台应用程序的主要方法:
static void Main(string[] args)
{
using (StreamReader r = new StreamReader(@"\model.json")) // json path
{
string json = r.ReadToEnd();
var deserializedJson = JsonConvert.DeserializeObject<Result>(json, new ItemConverter());
}
}
型号:
public class Result // main object
{
[JsonProperty("allitemscount")]
public long Allitemscount { get; set; }
public bool UseCustomItems { get; set; }
}
public class ResultA : Result // CustomItems Model
{
[JsonProperty("customitems")]
private List<Item> Items { get; set; }
}
public class ResultB : Result // AllItems Model
{
[JsonProperty("allitems")]
private List<Item> Items { get; set; }
}
public class Item
{
[JsonProperty("itemid")]
public string Itemid { get; set; }
[JsonProperty("itemname")]
public string Itemname { get; set; }
}
以及我们在反序列化到对象时使用的 ItemConverter:
internal class ItemConverter : JsonConverter
{
private Type currentType;
public override bool CanConvert(Type objectType)
{
return typeof(Item).IsAssignableFrom(objectType) || objectType == typeof(Result);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
if (item["UseCustomItems"] != null)
{
// save the type for later.
switch (item["UseCustomItems"].Value<bool>())
{
case true:
currentType = typeof(ResultA);
return item.ToObject<ResultA>(); // return result as customitems result
case false:
currentType = typeof(ResultB);
return item.ToObject<ResultB>(); // return result as allitems result
}
return item.ToObject<Result>();
}
// use the last type you read to serialise.
return item.ToObject(currentType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
结果应该如下图所示
希望这个解决方案对您有所帮助