首页 > 解决方案 > 为什么不在 Json.NET 中使用 PreserveReferencesHandling?

问题描述

在有许多奶牛和负责其中一些奶牛的农民的农场中,PreserveReferencesHandling 显着减少了生成的 json 的大小(在这种情况下为 45%)。

public class Farm
{
    public List<Cow> cows;
    public List<Farmer> farmers;
    public List<List<Farmer>> teams;
    ...
}
public class Cow
{
    //Some properties...
}
public class Farmer
{
    public List<Cow> cows;
    ...
}

如果 PreserveReferencesHandling 被关闭,这可能会导致大量的奶牛在 json 中被不必要地复制,这取决于可能存在的任何实现,实际上可能会破坏程序,例如因为相等性检查失败。

例如:没有 PreserveReferencesHandling

// characters: 985
{
  "cows": [
    {"name":"SmallCow"},
    {"name":"Cow"},
    {"name":"BigCow"}
  ],
  "farmers":[
    {"name":"Joe", "cows":[{"name":"SmallCow"}, {"name":"Cow"}]},
    {"name":"Chris", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]},
    {"name":"Chris Junior", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]},
    {"name":"Bob", "cows":[{"name":"SmallCow"}, {"name":"Cow"}, {"name":"BigCow"}]}
  ],
  "teams": [
    [{"name":"Joe", "cows":[{"name":"SmallCow"}, {"name":"Cow"}]}, {"name":"Chris", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]}],
    [{"name":"Chris Junior", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]}, {"name":"Chris", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]}],
    [{"name":"Joe", "cows":[{"name":"SmallCow"}, {"name":"Cow"}]},
    {"name":"Chris", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]},
    {"name":"Chris Junior", "cows":[{"name":"SmallCow"}, {"name":"BigCow"}]},
    {"name":"Bob", "cows":[{"name":"SmallCow"}, {"name":"Cow"}, {"name":"BigCow"}]}]
  ]
}

使用 PreserveReferencesHandling.Objects

// characters: 547
{ 
  "cows": [
    {"$id": 0, "name":"SmallCow"},
    {"$id": 1,"name":"Cow"},
    {"$id": 2,"name":"BigCow"}
  ],
  "farmers":[
    {"$id": 3, "name":"Joe", "cows":[{"$ref": 0}, {"$ref": 1}]},
    {"$id": 4, "name":"Chris", "cows":[{"$ref": 0}, {"$ref": 2}]},
    {"$id": 5, "name":"Chris Junior", "cows":[{"$ref": 0}, {"$ref": 2}]},
    {"$id": 6, "name":"Bob", "cows":[{"$ref": 0}, {"$ref": 1}, {"$ref": 2}]}
  ],
  "teams": [
    [{"$ref" : 3}, {"$ref" : 4}],
    [{"$ref" : 5}, {"$ref" : 4}],
    [{"$ref" : 3}, {"$ref" : 4}, {"$ref" : 5}, {"$ref" : 6}]
  ]
}

这个例子在某种程度上是为了显示差异而设计的,但我认为这种内存节省只会在数据系统变得更加复杂和互连时变得更加明显。

PreserveReferenceHandling 的优缺点是什么?哪个设置最有用,PreserveReferenceHandling.Objects、PreserveReferenceHandling.Arrays 还是 PreserveReferenceHandling.All?

标签: c#jsonperformanceserializationjson.net

解决方案


为什么不在 Json.NET 中使用 PreserveReferencesHandling?

PreserveReferencesHandling该行为的一些缺点包括:

  • 它生成看起来“奇怪”的 JSON,其他 JSON 解析器将难以反序列化(这在以不同语言反序列化时尤其是一个问题)。
  • 可能有一个明确的愿望,即进行引用处理(例如,消费者特别希望每个实例都是唯一的,而不是引用相同的值)。

如果您想要性能/简洁,那么某种形式的二进制格式(例如 protobuf)更有意义。JSON 具有人类可读性和跨语言很大程度上可互操作的优点。使用PreserveReferencesHandling会大大削弱这两个好处。

软件开发的本质是权衡。使用有什么好处PreserveReferencesHandling吗?当然有——这就是它存在的原因。但是库的作者正确地针对互操作性进行了优化,同时在需要时提供了选项。

此外,使用PreserveReferencesHandling并不总是与其他 Json.NET功能“很好地配合” ,并且由于跟踪和比较对象引用的额外工作,它可能会减慢一些序列化/反序列化。有必要进行分析以查看您的性能。


推荐阅读