C#结合Newtonsoft.Json生成路点位置与关联JSON的相关问题
1. $ref的取值逻辑
你看到的$ref是Newtonsoft.Json处理循环引用的标准标识,取值和顺序没有任何绑定关系,核心规则只有一条:$ref的取值必须和整个JSON结构中某个节点的$id取值完全一致,用来指向这个已定义的节点。
它的设计目的是避免冗余:同一个路点如果被多个其他路点关联(比如路口中心的路点会被四个方向的路点同时指向),不需要重复写入坐标、限速等完整属性,只用一个$ref引用即可,能大幅减小JSON体积,同时避免循环序列化导致的栈溢出。
比如参考JSON中"$ref": "0",就是指向整个JSON里任意位置带"$id": "0"的路点节点。
2. 生成符合参考结构的$ref引用
不需要手动给类的Ref、Id属性赋值,直接用Newtonsoft.Json自带的循环引用处理配置即可,序列化器会自动生成符合标准的$id和$ref字段。
修改你的序列化代码如下:
var jsonString = JsonConvert.SerializeObject(mainSource, new JsonSerializerSettings { // 自动为对象生成$id,重复引用时自动生成$ref PreserveReferencesHandling = PreserveReferencesHandling.Objects, // 忽略循环引用导致的序列化死循环 ReferenceLoopHandling = ReferenceLoopHandling.Ignore, // 按需开启,和参考JSON的$type字段匹配 TypeNameHandling = TypeNameHandling.All });
注意:开启自动生成引用后,你可以删除类中手动定义的[JsonProperty("$ref")]、[JsonProperty("$id")]相关属性,序列化器会自动插入这两个字段,和参考结构完全一致。
3. 循环引用结构的使用说明
这个结构不是链表,是有向图结构,比链表更灵活:一个路点可以关联任意多个下游路点,也可以被任意多个上游路点关联,完美适配多岔路、环形路、路口等复杂道路场景。
举个实际使用示例:假设你有A、B两个相邻的双向通行路点,要实现A到B、B到A的通行关联:
- 先创建A、B两个路点对象,填写坐标、限速、车道数等基础属性
- 给A的
RoadLinks列表新增一个RoadLink对象,将其Link属性指向B,填写SpacerLineWidth参数 - 给B的
RoadLinks列表新增一个RoadLink对象,将其Link属性指向A,填写SpacerLineWidth参数 - 直接用上面的配置序列化即可,Newtonsoft会自动将重复引用的路点转换为$ref,不会出现无限嵌套的问题。
优化建议:你当前定义的Content类和Link类属性几乎完全重复,建议合并为同一个路点类,减少代码冗余,序列化后的结构不会受影响。
内容的提问来源于stack exchange,提问作者Ghazanfar ALi

