我基本上有一个类似于图的结构。像这样:
public class Whole {
public List<Node> allPossibleNodes = new List<Node>();
}
public class Node {
public List<Node> neighbors = new List<Node>();
}
字符串
现在我想使用以下代码序列化它:
public class WriteTest {
static JsonSerializerOptions options = new () {
WriteIndented = true,
IncludeFields = true,
IgnoreReadOnlyProperties = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
ReferenceHandler = ReferenceHandler.Preserve,
};
public static void write() {
var w = new Whole();
Node? p = null; //previous
for (int i = 0; i < 3; i++) {
var n = new Node();
w.allPossibleNodes.Add(n);
if (p != null) {
n.neighbors.Add(p);
p.neighbors.Add(n);
}
p = n;
}
var json = JsonSerializer.Serialize(w, options);
File.WriteAllText("test.json", json);
}
public static void read() {
var json = File.ReadAllText("test2.json");
var w = JsonSerializer.Deserialize<Whole>(json, options);
}
}
型
它产生以下输出:
{
"$id": "1",
"allPossibleNodes": {
"$id": "2",
"$values": [
{
"$id": "3",
"neighbors": {
"$id": "4",
"$values": [
{
"$id": "5",
"neighbors": {
"$id": "6",
"$values": [
{
"$ref": "3"
},
{
"$id": "7",
"neighbors": {
"$id": "8",
"$values": [
{
"$ref": "5"
}
]
}
}
]
}
}
]
}
},
{
"$ref": "5"
},
{
"$ref": "7"
}
]
}
}
型
问题在于:
1.它最终会抛出一个异常:
“JsonException:'检测到可能的对象循环。这可能是由于循环或对象深度大于允许的最大深度64。'
或者如果我设置options.MaxDepth = Int.MaxValue;
,它可能会溢出堆栈。
1.我不只是丑陋的,人类不可读的垃圾。
我想要的是这样的东西:
{
"$id": "1",
"allPossibleNodes": {
"$id": "2",
"$values": [
{
"$id": "3",
"neighbors": {
"$id": "6",
"$values": [
{
"$ref": "4"
}
]
}
},
{
"$id": "4",
"neighbors": {
"$id": "7",
"$values": [
{
"$ref": "3"
},
{
"$ref": "5"
},
]
}
},
{
"$id": "5",
"neighbors": {
"$id": "8",
"$values": [
{
"$ref": "4"
}
]
}
}
]
}
}
型
但不幸的是,序列化程序甚至无法读取它,只能大喊"'Reference'4' was not found.”。
有没有办法让这一切顺利进行?
1条答案
按热度按时间x3naxklr1#
没有办法做到你想要的。System.Text.Json是一个单通道序列化器,所以它不能向前看**来解析引用。
作为一种解决方法,您可以禁用
Node.neighbors
的直接序列化,并将Whole
替换为DTO,该DTO将allPossibleNodes
列表和邻居表序列化为两个单独的顺序属性。这样做将把递归深度限制在可管理的范围内。为此,请按如下所示修改
Whole
和Node
,为Whole
引入自定义转换器:字符串
生成的JSON看起来像这样:
型
它不像你想要的JSON那样干净,但它仍然是可管理的。
备注:
Node
只能从Whole.allPossibleNodes
列表中序列化,并且该列表实际上包含所有可到达的节点。如果这些假设不正确,用
[JsonIgnore]
标记neighbors
可能会导致问题。WriteIndented = false
而不是true
。options.MaxDepth = Int.MaxValue
。节点将不会被递归序列化,因此序列化深度将被限制。演示小提琴here。