You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 11:27:37