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

如何在C#中用Protocol Buffer序列化含NetTopologySuite Polygon的City类?

解决NetTopologySuite Polygon类型的Protobuf序列化问题

方案一:使用protobuf-net自定义序列化器

protobuf-net默认不支持NetTopologySuite的Polygon类型,你可以通过**代理类(Surrogate)**实现自定义序列化逻辑:

  1. 定义Polygon的代理类,映射其可序列化的核心数据:
[ProtoContract]
public classPolygonSurrogate
{
    [ProtoMember(1)]
    public Coordinate[] Coordinates { get; set; }

    // 从NetTopologySuite Polygon转换为代理类
    public static implicit operatorPolygonSurrogate(Polygon polygon)
    {
        if (polygon == null) return null;
        return newPolygonSurrogate
        {
            Coordinates = polygon.Coordinates.ToArray()
        };
    }

    // 从代理类转换回NetTopologySuite Polygon
    public static implicit operatorPolygon(PolygonSurrogate surrogate)
    {
        if (surrogate == null) return null;
        return newPolygon(newLinearRing(surrogate.Coordinates));
    }
}
  1. 在应用启动时注册代理类,让protobuf-net识别Polygon类型的处理规则:
RuntimeTypeModel.Default.Add(typeof(Polygon), false).SetSurrogate(typeof(PolygonSurrogate));

完成注册后,你原来的City类即可正常序列化/反序列化,protobuf-net会自动通过代理类处理Polygon属性。

方案二:切换到Google.Protobuf实现

如果改用Google.Protobuf官方包,需遵循标准Protobuf流程,手动定义类型并处理转换:

  1. 编写.proto文件定义数据结构:
syntax = "proto3";

message City {
  string id = 1; // Guid以字符串形式存储
  string name = 2;
  int32 population = 3;
  Polygon area = 4;
}

message Polygon {
  repeated Coordinate coordinates = 1;
}

message Coordinate {
  double x = 1;
  double y = 2;
  optional double z = 3; // 对应Coordinate的Z值,可选
}
  1. 通过Google.Protobuf.Tools NuGet包生成C#类(或使用protoc工具)。

  2. 编写类型转换扩展方法,实现NetTopologySuite类型与生成的Protobuf类型互转:

public static classPolygonConversionExtensions
{
    // NetTopologySuite Polygon转Protobuf Polygon
    public static Proto.Polygon ToProtoPolygon(thisPolygon ntPolygon)
    {
        if (ntPolygon == null) return null;
        var protoPolygon = new Proto.Polygon();
        foreach (var coord in ntPolygon.Coordinates)
        {
            var protoCoord = new Proto.Coordinate
            {
                X = coord.X,
                Y = coord.Y
            };
            if (coord.HasZ) protoCoord.Z = coord.Z;
            protoPolygon.Coordinates.Add(protoCoord);
        }
        return protoPolygon;
    }

    // Protobuf Polygon转NetTopologySuite Polygon
    public staticPolygon ToNtPolygon(this Proto.Polygon protoPolygon)
    {
        if (protoPolygon == null) return null;
        var coordinates = protoPolygon.Coordinates
            .Select(c => newCoordinate(c.X, c.Y, c.Z.GetValueOrDefault(0)))
            .ToArray();
        return newPolygon(newLinearRing(coordinates));
    }
}
  1. 序列化/反序列化时手动转换类型:
// 序列化示例
var city = new City
{
    Id = Guid.NewGuid(),
    Name = "Beijing",
    Population = 21540000,
    Area = newPolygon(newLinearRing(new[] { /* 坐标点 */ }))
};

var protoCity = new Proto.City
{
    Id = city.Id.ToString(),
    Name = city.Name,
    Population = city.Population,
    Area = city.Area.ToProtoPolygon()
};

byte[] serializedBytes;
using (var stream = newMemoryStream())
{
    protoCity.WriteTo(stream);
    serializedBytes = stream.ToArray();
}

// 反序列化示例
using (var stream = newMemoryStream(serializedBytes))
{
    var deserializedProtoCity = Proto.City.Parser.ParseFrom(stream);
    var deserializedCity = new City
    {
        Id = Guid.Parse(deserializedProtoCity.Id),
        Name = deserializedProtoCity.Name,
        Population = deserializedProtoCity.Population,
        Area = deserializedProtoCity.Area.ToNtPolygon()
    };
}

方案对比

  • protobuf-net方案:无需额外定义.proto文件,代码侵入性低,适合希望保留原有类结构的场景。
  • Google.Protobuf方案:符合Protobuf标准规范,跨语言兼容性更强,但需要手动处理类型转换,流程更繁琐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 13:53:20