不使用dynamic反序列化含不同深度坐标数组的GeoJSON
解决GeoJSON多结构坐标反序列化问题
自定义Converter的思路是正确的
你遇到的InvalidCastException本质是没根据Geometry的Type区分坐标数组层级就硬转导致的——Polygon是三层嵌套数组,MultiPolygon是四层,直接用固定类型接收自然会类型不匹配。自定义转换器正是解决这类动态结构序列化问题的标准方案。
正确解析数组的两种实现方式
这里以Newtonsoft.Json为例给出两种可行方案:
方案1:基于抽象类的类型区分(类型更安全)
先定义不同Geometry类型的继承结构,让转换器根据Type字段实例化对应类型:
// 基础Geometry抽象类 public abstract class Geometry { public string Type { get; set; } } // Polygon类型 public class PolygonGeometry : Geometry { public List<List<double[]>> Coordinates { get; set; } } // MultiPolygon类型 public class MultiPolygonGeometry : Geometry { public List<List<List<double[]>>> Coordinates { get; set; } } // 自定义Geometry转换器 public class GeometryConverter : JsonConverter<Geometry> { public override Geometry ReadJson(JsonReader reader, Type objectType, Geometry existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObj = JObject.Load(reader); var geoType = jObj["Type"]?.Value<string>(); return geoType switch { "Polygon" => jObj.ToObject<PolygonGeometry>(serializer), "MultiPolygon" => jObj.ToObject<MultiPolygonGeometry>(serializer), _ => throw new NotSupportedException($"不支持的Geometry类型:{geoType}") }; } public override void WriteJson(JsonWriter writer, Geometry value, JsonSerializer serializer) { serializer.Serialize(writer, value); } } // Feature类(引用转换器) public class Feature { public string Type { get; set; } public Properties Properties { get; set; } [JsonConverter(typeof(GeometryConverter))] public Geometry Geometry { get; set; } } // Properties类(根据实际JSON字段补充) public class Properties { public string Name { get; set; } // 其他属性如ISO代码等按需添加 }
反序列化时,转换器会自动根据Type字段生成对应实例,直接通过类型判断处理坐标:
var features = JsonConvert.DeserializeObject<List<Feature>>(jsonString); foreach (var feature in features) { if (feature.Geometry is PolygonGeometry polygon) { // 处理Polygon的三层坐标 var coords = polygon.Coordinates; } else if (feature.Geometry is MultiPolygonGeometry multiPolygon) { // 处理MultiPolygon的四层坐标 var coords = multiPolygon.Coordinates; } }
方案2:通用Object类型接收(更灵活)
如果不想定义多个子类,可以用object接收坐标,在转换器中判断数组层级解析:
public class Geometry { public string Type { get; set; } [JsonConverter(typeof(CoordinatesConverter))] public object Coordinates { get; set; } } public class CoordinatesConverter : JsonConverter { public override bool CanConvert(Type objectType) => objectType == typeof(object); public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); if (token is not JArray level1) throw new JsonSerializationException("坐标格式无效"); // 判断数组层级:四层则为MultiPolygon,三层为Polygon if (level1.FirstOrDefault() is JArray level2 && level2.FirstOrDefault() is JArray level3) { return level3.FirstOrDefault() is JArray ? token.ToObject<List<List<List<double[]>>>>() : token.ToObject<List<List<double[]>>>(); } throw new JsonSerializationException("坐标格式无效"); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
使用时通过Type字段强制转换坐标类型:
var features = JsonConvert.DeserializeObject<List<Feature>>(jsonString); foreach (var feature in features) { if (feature.Geometry.Type == "Polygon") { var coords = (List<List<double[]>>)feature.Geometry.Coordinates; } else if (feature.Geometry.Type == "MultiPolygon") { var coords = (List<List<List<double[]>>>)feature.Geometry.Coordinates; } }
更优方案:使用成熟GeoJSON库
如果系统允许引入第三方库,直接用NetTopologySuite.IO.GeoJSON是最优解——它完全兼容GeoJSON标准,自动处理所有Geometry类型的序列化/反序列化,不需要自己写转换器:
// 先安装NuGet包:NetTopologySuite.IO.GeoJSON var reader = new GeoJsonReader(); var featureCollection = reader.Read<FeatureCollection>(jsonString); foreach (var feature in featureCollection.Features) { if (feature.Geometry is Polygon polygon) { // 直接处理Polygon坐标 } else if (feature.Geometry is MultiPolygon multiPolygon) { // 直接处理MultiPolygon坐标 } }
内容的提问来源于stack exchange,提问作者mike
相关产品推荐
相关产品推荐

