C#反序列化postcodes.io接口JSON为自定义对象列表属性为空如何解决
解决方案
问题根源
你的实体类结构和接口返回的JSON结构层级不匹配,是导致属性全部为null的核心原因:
- 接口返回的最外层
result字段是数组,数组中每个元素包含query字段和内层result字段,真正的postcode、longitude、latitude属性在内层result对象中 - 你直接将外层数组映射为
List<GeoData>,Json.NET无法找到对应映射关系,因此所有属性默认赋值为null - 额外注意:JSON中的
longitude、latitude是数值类型,你当前定义为string类型,也可能导致反序列化异常或精度丢失
修正方案
方案1:调整实体类结构匹配JSON层级(推荐)
- 新增中间实体类,对应外层
result数组的每个元素:
public class GeoDataQueryItem { [JsonProperty("query")] public string Query { get; set; } [JsonProperty("result")] public GeoData GeoData { get; set; } }
- 调整
GeoDataList和GeoData的定义,匹配JSON数据类型:
public class GeoDataList { [JsonProperty("result")] public List<GeoDataQueryItem> QueryItems { get; set; } } [Serializable] public class GeoData { [JsonProperty("postcode")] public string Postcode { get; set; } [JsonProperty("longitude")] public double Longitude { get; set; } [JsonProperty("latitude")] public double Latitude { get; set; } }
- 反序列化后提取目标GeoData列表即可,同时优化异步调用写法避免死锁:
var httpClient = new HttpClient(); var uri = "https://api.postcodes.io/postcodes/"; var response = await httpClient.PostAsync(uri, data); // 原代码混用await和.Result容易引发线程死锁,统一使用await更安全 string result = await response.Content.ReadAsStringAsync(); var dataResult = JsonConvert.DeserializeObject<GeoDataList>(result); // 提取所有GeoData对象 List<GeoData> geoDatas = dataResult.QueryItems.Select(x => x.GeoData).ToList();
方案2:不新增实体类,用JToken直接提取(适合不想调整类结构的场景)
如果不需要保留query字段,也可以直接通过LINQ to JSON读取内层属性:
var httpClient = new HttpClient(); var uri = "https://api.postcodes.io/postcodes/"; var response = await httpClient.PostAsync(uri, data); string result = await response.Content.ReadAsStringAsync(); JObject jObj = JObject.Parse(result); // 直接提取内层result字段转换为GeoData列表 List<GeoData> geoDatas = jObj["result"] .Select(item => item["result"].ToObject<GeoData>()) .ToList();
内容的提问来源于stack exchange,提问作者Rudy W
相关产品推荐
相关产品推荐

