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

C#中如何将Request对象序列化为含GeoJSON Polygon的JSON

嘿,我来帮你搞定这个GeoJSON序列化的问题!作为GeoJSON新手,确实容易在格式细节上踩坑,我给你两种可行的方案,都是基于Newtonsoft.Json实现的,你可以按需选择。

方案一:手动构建GeoJSON结构(无需额外NuGet包)

这种方式不需要依赖第三方库,完全通过自定义Json转换器来替换默认的序列化逻辑,把Fence里的Values列表转换成你需要的Polygon格式。

步骤1:创建自定义Json转换器

这个转换器会负责把Fence对象序列化为GeoJSON的FeatureCollection,同时支持反序列化回原对象:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;

public class FenceToGeoJsonConverter : JsonConverter<Fence>
{
    // 序列化:把Fence转成GeoJSON格式
    public override void WriteJson(JsonWriter writer, Fence value, JsonSerializer serializer)
    {
        // 注意!GeoJSON坐标顺序是【经度在前,纬度在后】,别搞反了
        var coordinatePairs = value.Values
            .Select(p => new[] { p.Longitude, p.Latitude })
            .ToList();
        
        // Polygon要求坐标闭合,所以最后要添加第一个点
        coordinatePairs.Add(coordinatePairs.First());

        // 构建符合规范的FeatureCollection结构
        var featureCollection = new
        {
            type = "FeatureCollection",
            features = new[]
            {
                new
                {
                    type = "Feature",
                    properties = new {}, // 这里可以添加自定义属性,比如Fence的Type
                    geometry = new
                    {
                        type = "Polygon",
                        coordinates = new[] { coordinatePairs }
                    }
                }
            }
        };

        // 序列化这个匿名对象
        serializer.Serialize(writer, featureCollection);
    }

    // 反序列化:把GeoJSON转回Fence对象
    public override Fence ReadJson(JsonReader reader, Type objectType, Fence existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var featureCollection = JObject.Load(reader);
        var feature = featureCollection["features"].First() as JObject;
        var polygonGeometry = feature["geometry"] as JObject;
        var coordinates = polygonGeometry["coordinates"].First() as JArray;

        // 去掉最后一个闭合点,转成PValues列表
        var values = coordinates
            .Take(coordinates.Count - 1)
            .Select(coord => new PValues
            {
                Longitude = (double)coord[0],
                Latitude = (double)coord[1]
            })
            .ToList();

        return new Fence
        {
            Type = existingValue?.Type ?? 0, // 如果需要从properties取Type,可修改这里
            Values = values
        };
    }
}

步骤2:给Fence属性标记转换器

在你的Request类中,给Fence属性加上[JsonConverter]特性,告诉Newtonsoft.Json用我们自定义的转换器处理它:

public class Request 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    [JsonConverter(typeof(FenceToGeoJsonConverter))]
    public Fence Fence { get; set; } 
} 

public class Fence { public int Type { get; set; } public List<PValues> Values { get; set; } } 

public class PValues { public double Latitude { get; set; } public double Longitude { get; set; } }

步骤3:测试序列化

现在就可以正常序列化Request对象了:

var testRequest = new Request
{
    Id = 1,
    Name = "园区围栏",
    Fence = new Fence
    {
        Type = 1,
        Values = new List<PValues>
        {
            new PValues { Latitude = 12.901617, Longitude = 80.227249 },
            new PValues { Latitude = 12.888553, Longitude = 80.227764 },
            new PValues { Latitude = 12.89006, Longitude = 80.232056 },
            new PValues { Latitude = 12.900779, Longitude = 80.233086 }
        }
    }
};

var jsonResult = JsonConvert.SerializeObject(testRequest, Formatting.Indented);
Console.WriteLine(jsonResult);

输出的JSON里,Fence字段就会变成你需要的GeoJSON Polygon结构。


方案二:使用GeoJSON.NET包简化开发

如果你还是想用GeoJSON.NET NuGet包,可能之前是用法不对,这个包已经帮我们封装好了GeoJSON的各种类型,不用手动拼接结构。

步骤1:安装NuGet包

在NuGet包管理器中安装GeoJSON.Net包。

步骤2:修改自定义转换器

用GeoJSON.NET的内置类型来构建结构,代码会更简洁:

using GeoJSON.Net.Feature;
using GeoJSON.Net.Geometry;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;

public class FenceToGeoJsonConverter : JsonConverter<Fence>
{
    public override void WriteJson(JsonWriter writer, Fence value, JsonSerializer serializer)
    {
        // 用GeoJSON.Net的Position类,构造参数是(latitude, longitude),内部会自动转成规范的[lon, lat]顺序
        var positions = value.Values
            .Select(p => new Position(p.Latitude, p.Longitude))
            .ToList();
        positions.Add(positions.First()); // 闭合坐标

        // 构建Polygon和FeatureCollection
        var polygon = new Polygon(new List<LineString> { new LineString(positions) });
        var feature = new Feature(polygon);
        var featureCollection = new FeatureCollection { Features = new List<Feature> { feature } };

        // 直接序列化即可,GeoJSON.Net的类型已经自带Json序列化支持
        serializer.Serialize(writer, featureCollection);
    }

    public override Fence ReadJson(JsonReader reader, Type objectType, Fence existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var featureCollection = serializer.Deserialize<FeatureCollection>(reader);
        var feature = featureCollection.Features.First();
        var polygon = feature.Geometry as Polygon;
        var positions = polygon.Coordinates.First().Coordinates;

        var values = positions
            .Take(positions.Count - 1)
            .Select(pos => new PValues
            {
                Latitude = pos.Latitude,
                Longitude = pos.Longitude
            })
            .ToList();

        return new Fence
        {
            Type = existingValue?.Type ?? 0,
            Values = values
        };
    }
}

剩下的步骤和方案一一样,给Fence属性标记转换器,然后正常序列化即可。


关键注意点

  1. 坐标顺序:GeoJSON规范要求坐标是[经度, 纬度],这是新手最容易搞错的地方,一定要注意转换!
  2. Polygon闭合:Polygon的坐标数组必须是闭合的,也就是最后一个点要和第一个点完全相同,否则不符合规范。
  3. 自定义属性:如果需要把Fence的Type字段放到GeoJSON的properties里,可以在构建Feature时添加,反序列化时再从properties里读取。

内容的提问来源于stack exchange,提问作者user3625533

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:45:08