C#中Newtonsoft.Json反序列化动态JSON为ExpandoObject后如何判断属性是否存在
问题根因
你之前的判断方法未生效,核心原因是Newtonsoft.Json默认反序列化ExpandoObject时,嵌套的对象不会被解析为ExpandoObject类型,而是JObject类型,因此针对ExpandoObject编写的类型强转判断逻辑自然无法运行。
解决方案
方案1:直接适配默认JObject类型(无需修改反序列化配置)
不需要调整反序列化逻辑,直接使用JObject的特性判断属性是否存在,同时可以直接用LINQ完成过滤:
// 示例代码,包含LINQ查询实现 var PPL = new List<string> { "city", "farm", "hamlet", "isolated_dwelling", "neighbourhood", "quarter", "suburb", "town", "village" }; JsonSerializer serializer = new JsonSerializer(); using (FileStream s = File.Open(jsonFile, FileMode.Open)) using (StreamReader sr = new StreamReader(s, Encoding.UTF8)) using (JsonReader reader = new JsonTextReader(sr)) { while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { dynamic jsonFeatures = serializer.Deserialize<ExpandoObject>(reader); // LINQ一步过滤出符合要求的条目 var targetItems = ((IEnumerable<dynamic>)jsonFeatures.features) .Where(item => item.place != null) // 判断place属性存在且非空 .Where(item => PPL.Contains((string)item.place, StringComparer.OrdinalIgnoreCase)); foreach (var item in targetItems) { var osm_id = item.properties.osm_id ?? string.Empty; string name = item.properties.name ?? string.Empty; string is_in = item.is_in ?? string.Empty; string Place = item.place ?? string.Empty; string geom = JsonConvert.SerializeObject(item.geometry); Console.WriteLine("name: {0} is_in: {1} Place: {2} geom: {3} ", name, is_in, Place, geom); } } } }
注意:如果你的
place属性实际存放在properties节点下(和osm_id、name同级),将判断条件改为item.properties.place != null即可。
方案2:配置反序列化规则,嵌套对象统一为ExpandoObject
如果你需要所有嵌套对象都按照ExpandoObject处理,只需要给序列化器新增ExpandoObjectConverter转换器,你之前写的HasAttr方法就可以正常运行:
var PPL = new List<string> { "city", "farm", "hamlet", "isolated_dwelling", "neighbourhood", "quarter", "suburb", "town", "village" }; JsonSerializer serializer = new JsonSerializer(); // 新增转换器,让嵌套对象也反序列化为ExpandoObject serializer.Converters.Add(new ExpandoObjectConverter()); using (FileStream s = File.Open(jsonFile, FileMode.Open)) using (StreamReader sr = new StreamReader(s, Encoding.UTF8)) using (JsonReader reader = new JsonTextReader(sr)) { while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { dynamic jsonFeatures = serializer.Deserialize<ExpandoObject>(reader); foreach (var item in jsonFeatures.features) { // 你的原有判断方法现在可以正常生效 if(HasAttr((ExpandoObject)item, "place")) { var osm_id = item.properties.osm_id ?? string.Empty; string name = item.properties.name ?? string.Empty; string is_in = item.is_in ?? string.Empty; string Place = item.place ?? string.Empty; string geom = JsonConvert.SerializeObject(item.geometry); bool IsPPL = PPL.Contains(Place, StringComparer.OrdinalIgnoreCase); if (IsPPL) { Console.WriteLine("name: {0} is_in: {1} Place: {2} geom: {3} ", name, is_in, Place, geom); } } } } } } private static bool HasAttr(ExpandoObject expando, string key) { return ((IDictionary<string, Object>)expando).ContainsKey(key); }
LINQ查询说明
两种方案都支持用LINQ完成属性存在判断+值匹配的过滤逻辑,不需要手动写if嵌套,代码更简洁。
内容的提问来源于stack exchange,提问作者Holly
相关产品推荐
相关产品推荐

