是什么在Json.Net preserveReferencesHandling和ReferenceLoopHandling之间的区别? [英] What is the difference between PreserveReferencesHandling and ReferenceLoopHandling in Json.Net?

查看:300
本文介绍了是什么在Json.Net preserveReferencesHandling和ReferenceLoopHandling之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在看有这个$ C $光盘1的WebAPI应用程序示例:

I am looking at one WebAPI application sample that has this coded:

json.SerializerSettings.PreserveReferencesHandling 
   = Newtonsoft.Json.PreserveReferencesHandling.Objects;

和另一个与此codeD:

and another with this coded:

json.SerializerSettings.ReferenceLoopHandling 
   = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

既不解释为什么每个被选中。我很新的WebAPI,所以有人用简单的术语什么区别,为什么我可能需要使用了另一种解释给我的帮助。

Neither explain why each is chosen. I'm very new to WebAPI, so can someone help by explaining to me in simple terms what the differences are and why I might need to use one over the other.

推荐答案

这些设置可以最好通过例子来说明。比方说,我们要重新present员工的层次结构中的公司。所以,我们做一个简单的类是这样的:

These settings can best be explained by example. Let's say that we want to represent a hierarchy of employees in a company. So we make a simple class like this:

class Employee
{
    public string Name { get; set; }
    public List<Employee> Subordinates { get; set; }
}

这是一家小公司,只有三名员工至今:张韶涵,鲍勃和查尔斯。安吉拉是老大,而鲍勃·查尔斯是她的下属。让我们来设置数据来描述这种关系:

This is a small company with only three employees so far: Angela, Bob and Charles. Angela is the boss, while Bob and Charles are her subordinates. Let's set up the data to describe this relationship:

Employee angela = new Employee { Name = "Angela Anderson" };
Employee bob = new Employee { Name = "Bob Brown" };
Employee charles = new Employee { Name = "Charles Cooper" };

angela.Subordinates = new List<Employee> { bob, charles };

List<Employee> employees = new List<Employee> { angela, bob, charles };

如果我们序列化的员工列表,以JSON ...

If we serialize the list of employees to JSON...

string json = JsonConvert.SerializeObject(employees, Formatting.Indented);
Console.WriteLine(json);

...我们得到如下的输出:

...we get this output:

[
  {
    "Name": "Angela Anderson",
    "Subordinates": [
      {
        "Name": "Bob Brown",
        "Subordinates": null
      },
      {
        "Name": "Charles Cooper",
        "Subordinates": null
      }
    ]
  },
  {
    "Name": "Bob Brown",
    "Subordinates": null
  },
  {
    "Name": "Charles Cooper",
    "Subordinates": null
  }
]

到目前为止好。然而,你会注意到的是,鲍勃和查尔斯的信息是重复的JSON因为对象重新presenting它们是由员工的主列表和下属的安吉拉的列表中引用两者。也许这就是好现在。

So far so good. You'll notice, however, that the information for Bob and Charles is repeated in the JSON because the objects representing them are referenced both by the main list of employees and Angela's list of subordinates. Maybe that's OK for now.

现在假设我们也希望有一种方法来跟踪每个员工的主管,除了他或她的下属。所以我们改变我们的员工模型添加监事属性...

Now suppose we'd also like to have a way to keep track of each Employee's supervisor in addition to his or her subordinates. So we change our Employee model to add a Supervisor property...

class Employee
{
    public string Name { get; set; }
    public Employee Supervisor { get; set; }
    public List<Employee> Subordinates { get; set; }
}

...和一对夫妇更行添加到我们的设置code,表明查尔斯和鲍勃·安吉拉报告:

...and add a couple more lines to our setup code to indicate that Charles and Bob report to Angela:

Employee angela = new Employee { Name = "Angela Anderson" };
Employee bob = new Employee { Name = "Bob Brown" };
Employee charles = new Employee { Name = "Charles Cooper" };

angela.Subordinates = new List<Employee> { bob, charles };
bob.Supervisor = angela;       // added this line
charles.Supervisor = angela;   // added this line

List<Employee> employees = new List<Employee> { angela, bob, charles };

但是,现在我们有一个有点问题。由于对象图中有引用循环(如安吉拉引用鲍勃,而鲍勃引用安吉拉),我们将得到一个 JsonSerializationException 当我们试图序列化的员工列表。我们可以解决这个问题的方法之一是通过设置 ReferenceLoopHandling 忽略是这样的:

But now we have a bit of a problem. Because the object graph has reference loops in it (e.g. angela references bob while bob references angela), we will get a JsonSerializationException when we try to serialize the employees list. One way we can get around this issue is by setting ReferenceLoopHandling to Ignore like this:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Formatting = Formatting.Indented
};

string json = JsonConvert.SerializeObject(employees, settings);

通过此设置到位,我们得到以下JSON:

With this setting in place, we get the following JSON:

[
  {
    "Name": "Angela Anderson",
    "Supervisor": null,
    "Subordinates": [
      {
        "Name": "Bob Brown",
        "Subordinates": null
      },
      {
        "Name": "Charles Cooper",
        "Subordinates": null
      }
    ]
  },
  {
    "Name": "Bob Brown",
    "Supervisor": {
      "Name": "Angela Anderson",
      "Supervisor": null,
      "Subordinates": [
        {
          "Name": "Charles Cooper",
          "Subordinates": null
        }
      ]
    },
    "Subordinates": null
  },
  {
    "Name": "Charles Cooper",
    "Supervisor": {
      "Name": "Angela Anderson",
      "Supervisor": null,
      "Subordinates": [
        {
          "Name": "Bob Brown",
          "Subordinates": null
        }
      ]
    },
    "Subordinates": null
  }
]

如果您检查JSON,应该清楚这个设置什么:任何时候串行遇到的引用回一个对象,它已经在序列化的过程中,它只是跳过该成员。 (这prevents不陷入无限循环序列化)。你可以看到,在JSON的顶部下属安吉拉的名单,无论是鲍勃·查尔斯也显示监事。在JSON的底部,鲍勃和查尔斯都显示安吉拉作为他们的上司,但要注意她的下属在这一点名单不包括Bob和查尔斯。

If you examine the JSON, it should be clear what this setting does: any time the serializer encounters a reference back to an object it is already in the process of serializing, it simply skips that member. (This prevents the serializer from getting into an infinite loop.) You can see that in Angela's list of subordinates in the top part of the JSON, neither Bob nor Charles show a supervisor. In the bottom part of the JSON, Bob and Charles both show Angela as their supervisor, but notice her subordinates list at that point does not include both Bob and Charles.

虽然可以与此JSON来工作,甚至可能从它的一些工作重构原始对象分层结构,但显然不是最优的。我们可以消除JSON重复的信息,同时还为$ P $使用pserving对象引用 preserveReferencesHandling 设置来代替:

While it is possible to work with this JSON and maybe even reconstruct the original object hierarchy from it with some work, it is clearly not optimal. We can eliminate the repeated information in the JSON while still preserving the object references by using the PreserveReferencesHandling setting instead:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    Formatting = Formatting.Indented
};

string json = JsonConvert.SerializeObject(employees, settings);

现在我们得到以下JSON:

Now we get the following JSON:

[
  {
    "$id": "1",
    "Name": "Angela Anderson",
    "Supervisor": null,
    "Subordinates": [
      {
        "$id": "2",
        "Name": "Bob Brown",
        "Supervisor": {
          "$ref": "1"
        },
        "Subordinates": null
      },
      {
        "$id": "3",
        "Name": "Charles Cooper",
        "Supervisor": {
          "$ref": "1"
        },
        "Subordinates": null
      }
    ]
  },
  {
    "$ref": "2"
  },
  {
    "$ref": "3"
  }
]

,现在每个对象已被分配顺序的$ id 值在JSON通知。出现一个对象第一次,这是连载于满,而随后的参考与引用回到原来的对象,相应的<$一个特殊的 $ REF 属性替换C $ C>的$ id 。有了这个设置,JSON是更简洁,可以反序列化回,无需额外的工作原来的对象层次结构,假设你使用的是理解的$ id $ REF 按Json.Net /网页API产生的符号。

Notice that now each object has been assigned a sequential $id value in the JSON. The first time that an object appears, it is serialized in full, while subsequent references are replaced with a special $ref property that refers back to the original object with the corresponding $id. With this setting in place, the JSON is much more concise and can be deserialized back into the original object hierarchy with no additional work required, assuming you are using a library that understands the $id and $ref notation produced by Json.Net / Web API.

那么,为什么你会选择一个设置或其他?这取决于你的课程需要。如果JSON将由客户端使用不理解的的$ id / $ REF 格式,它可以容忍具有地方不完整的数据,你会选择使用 ReferenceLoopHandling.Ignore 。如果你正在寻找更紧凑JSON和您将使用Json.Net或Web API(或其他兼容库)反序列化数据,那么你会选择使用 preserveReferencesHandling.Objects 。如果你的数据是一个有向无环图没有重复引用,那么你就不需要任何设置。

So why would you choose one setting or the other? It depends on your needs of course. If the JSON will be consumed by a client that does not understand the $id/$ref format, and it can tolerate having incomplete data in places, you would choose to use ReferenceLoopHandling.Ignore. If you're looking for more compact JSON and you will be using Json.Net or Web API (or another compatible library) to deserialize the data, then you would choose to use PreserveReferencesHandling.Objects. If your data is a directed acyclic graph with no duplicate references then you don't need either setting.

这篇关于是什么在Json.Net preserveReferencesHandling和ReferenceLoopHandling之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆