Json.Net学习笔记(十) 保持对象引用

更多内容见这里:http://www.cnblogs.com/wuyifu/archive/2013/09/03/3299784.html

默认情况下,Json.Net将通过对象的值来序列化它遇到的所有对象。如果工个list包含两个Person引用,这两个引用都指向同一个对象,Json序列化器将输出每一个引用的所有名称和值。

定义类:

public class Person
    {
        public DateTime BirthDate { get; set; }
        public DateTime LastModified { get; set; }
        public string Name { get; set; }
    }

测试:

Person p = new Person()
            {
                BirthDate = new DateTime(1985, 11, 27, 0, 0, 0, DateTimeKind.Utc),
                LastModified = new DateTime(2010, 12, 20, 0, 0, 0, DateTimeKind.Utc),
                Name = "James"
            };
            List<Person> people = new List<Person>();
            people.Add(p);
            people.Add(p);
            string json = JsonConvert.SerializeObject(people, Formatting.Indented);
            Console.WriteLine(json);

输出结果:

[
  {
    "BirthDate": "\/Date(501897600000)\/",
    "LastModified": "\/Date(1292803200000)\/",
    "Name": "James"
  },
  {
    "BirthDate": "\/Date(501897600000)\/",
    "LastModified": "\/Date(1292803200000)\/",
    "Name": "James"
  }
]

在大多数情况下这是期望的结果,但是在某些场景下,将list中的第二项作为第一项的一个引用来输出会是一个更好的解决方案。如果上面的Json现在被反序列化,返回的list会包含两个完全分离的对象,它们具有相同的值。通过值来输出引用也会在对象上导致循环引用的发生。

>PreserveReferencesHandling

string json2 = JsonConvert.SerializeObject(people, Formatting.Indented,
                new JsonSerializerSettings() { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
            Console.WriteLine(json2);

输出结果:

[
              {
                "$id": "1",
                "BirthDate": "\/Date(501897600000)\/",
                "LastModified": "\/Date(1292803200000)\/",
                "Name": "James"
              },
              {
                "$ref": "1"
              }
            ]

List<Person> deserializedPeople = JsonConvert.DeserializeObject<List<Person>>(json2,
                new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });

Console.WriteLine(deserializedPeople.Count);// 2

Person p1 = deserializedPeople[0];
            Person p2 = deserializedPeople[1];
            Console.WriteLine(p1.Name);// James
            Console.WriteLine(p2.Name);// James
            bool equal = Object.ReferenceEquals(p1, p2);// true

在list中的第一个Person被序列化时增加了一个额外的对象Id,现在第二个Person对象仅仅是第一个的引用。

现在使用PreserveReferencesHandling后,在序列化时只创建了一个Person对象,list中包含它的两个引用,原来我们叫作反射(mirroring) 。

>IsReference on JsonObjectAttribute, JsonArrayAttribute and JsonPropertyAttribute

在对象序列化器上设置PreserveReferencesHandling,将会改变所有对象被序列化和反序列化的方式。为了更加细致地控制对象和成员被序列化为一个引用,可以在JsonObjectAttribute, JsonArrayAttribute 和 JsonPropertyAttribute上使用IsReference 属性.

在JsonObjectAttribute, JsonArrayAttribute 上设置IsReference 为true,意味着Json序列化器总是会序列这个类型为一个引用。在JsonPropertyAttribute上设置IsReference为true将只序列化这个属性为一个引用。

[JsonObject(IsReference = true)]
    public class EmployeeReference
    {
        public string Name { get; set; }
        public EmployeeReference Manager { get; set; }
    }

测试:

List<EmployeeReference> empList = new List<EmployeeReference>();
            empList.Add(empRef);
            empList.Add(empRef);
            string empRefJson = JsonConvert.SerializeObject(empList, Formatting.Indented);
            Console.WriteLine(empRefJson);

输出结果:

[
  {
    "$id": "1",
    "Name": "IsReference",
    "Manager": null
  },
  {
    "$ref": "1"
  }
]

>IReferenceResolver

要想定制引用的生成方式,可以继承自IReferenceResolver接口来使用Json序列化器。

时间: 2024-11-05 01:01:48

Json.Net学习笔记(十) 保持对象引用的相关文章

Json.Net学习笔记

http://www.cnblogs.com/xiaojinhe2/archive/2011/10/28/2227789.html Newtonsoft.Json(Json.Net)学习笔记 http://www.cnblogs.com/freshman0216/p/4161800.html http://www.cnblogs.com/xwgli/archive/2013/08/30/3290964.html

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

第十七篇:实例分析(3)--初探WDDM驱动学习笔记(十)

续: 还是记录一下, BltFuncs.cpp中的函数作用: CONVERT_32BPP_TO_16BPP 是将32bit的pixel转换成16bit的形式. 输入是DWORD 32位中, BYTE 0,1,2分别是RGB分量, 而BYTE3则是不用的 为了不减少color的范围, 所以,都是取RGB8,8,8的高RGB5, 6, 5位, 然后将这16位构成一个pixel. CONVERT_16BPP_TO_32BPP是将16bit的pixel转换成32bit的形式 输入是WORD 16BIT中

初探swift语言的学习笔记十(block)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35783341 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 在前面一些学习中,原本把闭包给理解成了block尽管有很多相似之处,但block还是有他自己的独特之外.近日,在写oc/swift混合编码时,有时候需要swift回调oc,oc回调swift . 因此我把swift中的 block 常见的声明和写

Swift学习笔记十:属性

1.存储属性       1. 作为特定类或结构实例的一部分,存储属性存储着常量或者变量的值.存储属性可分为变量存储属性(关键字var描述)和常量存储属性(关键字let描述). struct student{ let name = "" var score = 0 } let a = student(name:"小笨狼",score:96)           注意:                ① 定义储存属性时,需要为每一个属性定义一个默认值.在初始化的时候,

python学习笔记十——异常处理

1.try: command except 错误类型,记录错误信息变量: command finally: command try...finally的用处是无论是否发生异常都要确保资源释放代码的执行.一般来说,如果没有发生错误,执行过try语句块之后执行finally语句块,完成整个流程.如果try语句块发生了异常,抛出了这个异常,此时就马上进入finally语句块进行资源释放处理.如下从几个细节讨论finally的特性. 1).try中的return: 当在try语句块中含有return语句

虚拟机VMWare学习笔记十二 - 将物理机抓取成虚拟机

1. 安装VMware vCenter Converter Standalone Client 运行虚拟机,File -- Virtualize a Physical Machine 这时如果电脑中没有VMware vCenter Converter Standalone Client ,则会进行安装. 安装过程 之后图标会出现在桌面上,双击运行 选择连接到本地服务器,登陆 点击转换计算机 这个,可以将本地计算机抓取成虚拟机,也可以将其他可以访问的计算机(需知道管理员用户名及密码)抓取成虚拟机.

Linux System Programming 学习笔记(十) 信号

1. 信号是软中断,提供处理异步事件的机制 异步事件可以是来源于系统外部(例如用户输入Ctrl-C)也可以来源于系统内(例如除0) 内核使用以下三种方法之一来处理信号: (1) 忽略该信号.SIGKILL和SIGSTOP不能被忽略. (2) 捕捉并且处理该信号.The kernel will suspend execution of the process's current code path and jump to a previously registered function. SIGK

APUE 学习笔记(十) 高级I/O

1. Unix IPC(InterProcess Communication) 同一主机的各个进程间的IPC:管道.FIFO.消息队列.信号量.共享存储器 不同主机上的各个进程间IPC:socket套接字 2. 管道 管道进行IPC有两个局限: (1) 半双工,即数据只能在一个方向上流动 (2) 只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后 父子进程之间可以使用该管道 fstat函数对管道的每一端都返回一个FIFO类型的文件描述符,可以用S_ISF