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属性标记转换器,然后正常序列化即可。
关键注意点
- 坐标顺序:GeoJSON规范要求坐标是
[经度, 纬度],这是新手最容易搞错的地方,一定要注意转换! - Polygon闭合:Polygon的坐标数组必须是闭合的,也就是最后一个点要和第一个点完全相同,否则不符合规范。
- 自定义属性:如果需要把
Fence的Type字段放到GeoJSON的properties里,可以在构建Feature时添加,反序列化时再从properties里读取。
内容的提问来源于stack exchange,提问作者user3625533
相关产品推荐
相关产品推荐

