JsonConvert.SerializeObject 呼叫 object.Equals 问题探讨

最近在 StackOverFlow 解答一个很有趣的问题Json.Net / Newtonsoft: Using JsonConvert.SerializeObject results in weird .Equals calls - why?

问题简述是:

使用Newtonsoft.Json.JsonConvert.SerializeObject方法 来把物件转成JSON资料时,为什么会呼叫物件的Equals 方法 且传入的object obj类型不是此类别类型,而是属性的类型

以下是发问者提供的程式码:

public class JsonTestClass{    public string Name { get; set; }    public List<int> MyIntList { get; set; }    public override bool Equals(object obj)    {        if (obj == null)            return false;        JsonTestClass jtc = (JsonTestClass)obj;        return true;    }}JsonTestClass c = new JsonTestClass();c.Name = "test";c.MyIntList = new List<int>();c.MyIntList.Add(1);string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });

看到问题后我就直接去看Json.net原始码 一探到底原因出在哪边.

后面发现当我们在呼叫JsonConvert.SerializeObject方法,会执行一个 private bool CheckForCircularReference私有方法.

bool exists = (Serializer._equalityComparer != null)                ? _serializeStack.Contains(value, Serializer._equalityComparer)                : _serializeStack.Contains(value);

这个方法主要用意是判断目前序列化JSON物件是否有重複引用本身,方法中有段程式码使用到 List<T>.Contains.

当我们在呼叫List<T>.Contains时 预设EqualityComparer<T>.Default 进行比较来进行判断是否存在集合中.

要写客製化比较方式有两种

在.net中每个类别都继承于Object, Object 中有object.Equals 所以可以重写object.Equals方法.将此类别实现 IEquatable<T> 并重写你要的比较方式.

所以会呼叫object.Equals是因为上段程式码


什么是判断目前序列化JSON物件是否有重複引用本身?

以下的範例是private bool CheckForCircularReference想要防止的问题

public class JsonTestClass{    public string Name { get; set; }    public List<int> MyIntList { get; set; }    public JsonTestClass Test{get;set;}}JsonTestClass c = new JsonTestClass();c.Name = "test";c.Test = c;string json = JsonConvert.SerializeObject               (c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });

我们可以看到c.Test = c; 将自己本身付值给 public JsonTestClass Test{get;set;} 这个属性.

我们执行上面程式码会得到此错误

Self referencing loop detected for property 'Test' with type 'Program+JsonTestClass'. Path ''.

是因为他要防止重複引用本身导致无限迴圈解析JSON.

Note

预设值类型的比较是比较值.
预设参考类别比较的是地址.


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章