如何反序列化 json,其中数据可以是对象或空数组,并且对象是 "Dictionary" 格式?
How to deserialize json where the data can be an object or an empty array and as an object is in a "Dictionary" format?
我正在接收 json 以下格式的数据。我无法控制 json 数据。
{
"response": {
"status": 1,
"httpStatus": 200,
"data": {
"Countries": {
"818": {
"id": "818",
"code": "EG",
"name": "Egypt"
},
"414": {
"id": "414",
"code": "KW",
"name": "Kuwait"
},
"682": {
"id": "682",
"code": "SA",
"name": "Saudi Arabia"
},
"784": {
"id": "784",
"code": "AE",
"name": "United Arab Emirates"
}
},
"Regions": [],
"Cities": [],
"Exclude": []
},
"errors": [],
"errorMessage": null
}
}
我正在尝试反序列化数据以获取国家/地区代码。我使用字典来处理国家 ID 部分作为键,并使用 class 来处理其他值。
public class CountryResponseData
{
public CountryData Data { get; set; }
}
public class CountryData
{
public Dictionary<string, Country> Countries { get; set; }
}
public class Country
{
public string Code { get; set; }
}
只要它们是数据中的国家/地区,这就可以正常工作,但一些数据采用以下格式。
{
"response": {
"status": 1,
"httpStatus": 200,
"data": {
"Countries": [],
"Regions": [],
"Cities": [],
"Exclude": []
},
"errors": [],
"errorMessage": null
}
}
因为在这种情况下国家是数组而不是对象,反序列化器不知道如何处理它。
我试过使用自定义 json 转换器,就像这些答案 ( and ) 中描述的那样,但它似乎没有任何作用。
如有任何帮助,我们将不胜感激。
我相信您所指的答案中的代码可以正常工作。我这样测试了你的案例:
public class CountryResponseData
{
public CountryData Data { get; set; }
}
public class CountryData
{
[JsonConverter(typeof(EmptyArrayOrDictionaryConverter))]
public Dictionary<string, Country> Countries { get; set; }
}
public class Country
{
public string Code { get; set; }
}
// this a modified version of this SO-answer:
public class EmptyArrayOrDictionaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType.IsAssignableFrom(typeof(Dictionary<string, object>));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
return token.Type switch
{
JTokenType.Object => token.ToObject(objectType, serializer), JTokenType.Array when !token.HasValues => Activator.CreateInstance(objectType),
_ => throw new JsonSerializationException("Object or empty array expected")
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => serializer.Serialize(writer, value);
}
public class MyJsonTestClass
{
private const string JsonWithCountries = @"{
""data"": {
""Countries"": {
""818"": {
""id"": ""818"",
""code"": ""EG"",
""name"": ""Egypt""
},
""414"": {
""id"": ""414"",
""code"": ""KW"",
""name"": ""Kuwait""
},
""682"": {
""id"": ""682"",
""code"": ""SA"",
""name"": ""Saudi Arabia""
},
""784"": {
""id"": ""784"",
""code"": ""AE"",
""name"": ""United Arab Emirates""
}
},
""Regions"": [],
""Cities"": [],
""Exclude"": []
}
}";
private const string JsonWithoutCountries = @"{
""data"": {
""Countries"": [],
""Regions"": [],
""Cities"": [],
""Exclude"": []
}
}";
[Test]
public void MyJsonTest()
{
// START tests using NewtonSoft
var result = JsonConvert.DeserializeObject<CountryResponseData>(JsonWithCountries);
Assert.NotNull(result?.Data);
var result2 = JsonConvert.DeserializeObject<CountryResponseData>(JsonWithoutCountries);
Assert.NotNull(result2?.Data);
}
}
最简单的方法是将 json 字符串中的 Country[] 替换为 null。相同的代码适用于 jsons
var jsonOriginal = "{\"response\":{\"status\":1,\"httpStatus\":200,\"data\":{\"Countries\":[],\"Regions\":[],\"Cities\":[],\"Exclude\":[]},\"errors\":[],\"errorMessage\":null}}";
var json=jsonOriginal.Replace("\"Countries\":[],","\"Countries\":null,");
// you can add the same for Regions and Cities too if one day they will be changed to dictionary type
你会得到这个输出
{"response":{"status":1,"httpStatus":200,"data":{"Countries":null,"Regions":[],"Cities":[],"Exclude":[]},"errors":[],"errorMessage":null}}
但如果由于某些原因它不适合你,那就有一个困难的方法:
此代码在 visual studio 中进行了测试,适用于我
var json = "{\"response\":{\"status\":1,\"httpStatus\":200,\"data\":{\"Countries\":[],\"Regions\":[],\"Cities\":[],\"Exclude\":[]},\"errors\":[],\"errorMessage\":null}}";
JsonObj jsonObj = null;
JsonObj2 jsonObj2 = null;
try
{
jsonObj = JsonConvert.DeserializeObject<JsonObj>(json);
}
catch (Exception ex)
{
if (ex.Source == "Newtonsoft.Json")
{
try
{
jsonObj2 = JsonConvert.DeserializeObject<JsonObj2>(json);
}
catch (Exception ex1)
{
throw;
}
}
}
if (jsonObj != null) ....
else ....
类
public class Country
{
public string id { get; set; }
public string code { get; set; }
public string name { get; set; }
}
public class Data
{
public Dictionary<string, Country> Countries { get; set; }
public List<object> Regions { get; set; }
public List<object> Cities { get; set; }
public List<object> Exclude { get; set; }
}
public class Data2
{
public List<object> Countries { get; set; }
public List<object> Regions { get; set; }
public List<object> Cities { get; set; }
public List<object> Exclude { get; set; }
}
public class Response
{
public int status { get; set; }
public int httpStatus { get; set; }
public Data data { get; set; }
public List<object> errors { get; set; }
public object errorMessage { get; set; }
}
public class Response2
{
public int status { get; set; }
public int httpStatus { get; set; }
public Data2 data { get; set; }
public List<object> errors { get; set; }
public object errorMessage { get; set; }
}
public class JsonObj
{
public Response response { get; set; }
}
public class JsonObj2
{
public Response2 response { get; set; }
}
我正在接收 json 以下格式的数据。我无法控制 json 数据。
{
"response": {
"status": 1,
"httpStatus": 200,
"data": {
"Countries": {
"818": {
"id": "818",
"code": "EG",
"name": "Egypt"
},
"414": {
"id": "414",
"code": "KW",
"name": "Kuwait"
},
"682": {
"id": "682",
"code": "SA",
"name": "Saudi Arabia"
},
"784": {
"id": "784",
"code": "AE",
"name": "United Arab Emirates"
}
},
"Regions": [],
"Cities": [],
"Exclude": []
},
"errors": [],
"errorMessage": null
}
}
我正在尝试反序列化数据以获取国家/地区代码。我使用字典来处理国家 ID 部分作为键,并使用 class 来处理其他值。
public class CountryResponseData
{
public CountryData Data { get; set; }
}
public class CountryData
{
public Dictionary<string, Country> Countries { get; set; }
}
public class Country
{
public string Code { get; set; }
}
只要它们是数据中的国家/地区,这就可以正常工作,但一些数据采用以下格式。
{
"response": {
"status": 1,
"httpStatus": 200,
"data": {
"Countries": [],
"Regions": [],
"Cities": [],
"Exclude": []
},
"errors": [],
"errorMessage": null
}
}
因为在这种情况下国家是数组而不是对象,反序列化器不知道如何处理它。
我试过使用自定义 json 转换器,就像这些答案 ( and
如有任何帮助,我们将不胜感激。
我相信您所指的答案中的代码可以正常工作。我这样测试了你的案例:
public class CountryResponseData
{
public CountryData Data { get; set; }
}
public class CountryData
{
[JsonConverter(typeof(EmptyArrayOrDictionaryConverter))]
public Dictionary<string, Country> Countries { get; set; }
}
public class Country
{
public string Code { get; set; }
}
// this a modified version of this SO-answer:
public class EmptyArrayOrDictionaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType.IsAssignableFrom(typeof(Dictionary<string, object>));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
return token.Type switch
{
JTokenType.Object => token.ToObject(objectType, serializer), JTokenType.Array when !token.HasValues => Activator.CreateInstance(objectType),
_ => throw new JsonSerializationException("Object or empty array expected")
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => serializer.Serialize(writer, value);
}
public class MyJsonTestClass
{
private const string JsonWithCountries = @"{
""data"": {
""Countries"": {
""818"": {
""id"": ""818"",
""code"": ""EG"",
""name"": ""Egypt""
},
""414"": {
""id"": ""414"",
""code"": ""KW"",
""name"": ""Kuwait""
},
""682"": {
""id"": ""682"",
""code"": ""SA"",
""name"": ""Saudi Arabia""
},
""784"": {
""id"": ""784"",
""code"": ""AE"",
""name"": ""United Arab Emirates""
}
},
""Regions"": [],
""Cities"": [],
""Exclude"": []
}
}";
private const string JsonWithoutCountries = @"{
""data"": {
""Countries"": [],
""Regions"": [],
""Cities"": [],
""Exclude"": []
}
}";
[Test]
public void MyJsonTest()
{
// START tests using NewtonSoft
var result = JsonConvert.DeserializeObject<CountryResponseData>(JsonWithCountries);
Assert.NotNull(result?.Data);
var result2 = JsonConvert.DeserializeObject<CountryResponseData>(JsonWithoutCountries);
Assert.NotNull(result2?.Data);
}
}
最简单的方法是将 json 字符串中的 Country[] 替换为 null。相同的代码适用于 jsons
var jsonOriginal = "{\"response\":{\"status\":1,\"httpStatus\":200,\"data\":{\"Countries\":[],\"Regions\":[],\"Cities\":[],\"Exclude\":[]},\"errors\":[],\"errorMessage\":null}}";
var json=jsonOriginal.Replace("\"Countries\":[],","\"Countries\":null,");
// you can add the same for Regions and Cities too if one day they will be changed to dictionary type
你会得到这个输出
{"response":{"status":1,"httpStatus":200,"data":{"Countries":null,"Regions":[],"Cities":[],"Exclude":[]},"errors":[],"errorMessage":null}}
但如果由于某些原因它不适合你,那就有一个困难的方法:
此代码在 visual studio 中进行了测试,适用于我
var json = "{\"response\":{\"status\":1,\"httpStatus\":200,\"data\":{\"Countries\":[],\"Regions\":[],\"Cities\":[],\"Exclude\":[]},\"errors\":[],\"errorMessage\":null}}";
JsonObj jsonObj = null;
JsonObj2 jsonObj2 = null;
try
{
jsonObj = JsonConvert.DeserializeObject<JsonObj>(json);
}
catch (Exception ex)
{
if (ex.Source == "Newtonsoft.Json")
{
try
{
jsonObj2 = JsonConvert.DeserializeObject<JsonObj2>(json);
}
catch (Exception ex1)
{
throw;
}
}
}
if (jsonObj != null) ....
else ....
类
public class Country
{
public string id { get; set; }
public string code { get; set; }
public string name { get; set; }
}
public class Data
{
public Dictionary<string, Country> Countries { get; set; }
public List<object> Regions { get; set; }
public List<object> Cities { get; set; }
public List<object> Exclude { get; set; }
}
public class Data2
{
public List<object> Countries { get; set; }
public List<object> Regions { get; set; }
public List<object> Cities { get; set; }
public List<object> Exclude { get; set; }
}
public class Response
{
public int status { get; set; }
public int httpStatus { get; set; }
public Data data { get; set; }
public List<object> errors { get; set; }
public object errorMessage { get; set; }
}
public class Response2
{
public int status { get; set; }
public int httpStatus { get; set; }
public Data2 data { get; set; }
public List<object> errors { get; set; }
public object errorMessage { get; set; }
}
public class JsonObj
{
public Response response { get; set; }
}
public class JsonObj2
{
public Response2 response { get; set; }
}