为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在序列化时 Json.Net 会在我的对象上调用 Equals 方法?

为什么在序列化时 Json.Net 会在我的对象上调用 Equals 方法?

C#
RISEBY 2021-11-14 14:33:56
我在使用 Newtonsoft.JsonSerializeObject方法时遇到了错误。之前有人问过这里,但与 Newtonsoft 合作的人没有回答为什么会发生这种情况。基本上,当这样调用时SerializeObject:string json = Newtonsoft.Json.JsonConvert.SerializeObject(from, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });我Equals在我的课程中覆盖的许多方法中出现错误:public override bool Equals(object obj){    if (obj == null)        return false;    CapacityConfiguration cc = (CapacityConfiguration)obj; // <-- TypeCastException here; other Properties of the same class are sent in as parameter!}当然,我意识到通过这样检查来修复它很“容易”:public override bool Equals(object obj){    if (obj is CapacityConfiguration == false)        return false;    CapacityConfiguration cc = (CapacityConfiguration)obj;}但真正的问题是: 为什么Json.Net会在类的Equals方法中传入其他类型的对象?更具体地说,Json.Net 似乎在类中发送了许多其他属性,而不是另一个相同类型的对象。对我来说,这完全很奇怪。任何输入将不胜感激。根据 Visual Studio,我正在使用“版本 8.0.0.0”。更新 1它很容易测试,因为它是可重现的: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;    }}然后只需将此代码放在 Program.cs 或其他任何地方:JsonTestClass c = new JsonTestClass();c.Name = "test";c.MyIntList = new List<int>();c.MyIntList.Add(1);string json = Newtonsoft.Json.JsonConvert.SerializeObject(c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });你会得到 TypeCast 异常:
查看完整描述

1 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

为什么 JsonConvert.SerializeObject 会调用该object.Equals方法?


因为当你使用 时JsonConvert.SerializeObject,有一个方法CheckForCircularReference被调用来检查一个属性是否重新引用了你自己的对象,导致无限循环。


 private bool CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)

在CheckForCircularReference方法中,部分代码使用了该Contains方法,object.Equals如果您object没有实现该 IEquatable<T>接口,该方法将调用。


bool exists = (Serializer._equalityComparer != null)

                ? _serializeStack.Contains(value, Serializer._equalityComparer)

                : _serializeStack.Contains(value);

解释


_serializeStack 是当前正在序列化的对象列表。

该List<T>.Contains方法检查当前属性是否包含在集合中。

List<T>.Containsuses EqualityComparer<T>.Default,IEquatable<T>如果类型实现它,则依次使用,object.Equals否则使用。

该object value参数是您当前的Property对象。

下面是一个自引用循环的例子:


public class JsonTestClass

{

    public string Name { get; set; }

    public List<int> MyIntList { get; set; }

    public JsonTestClass Test{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.Test = c;

string json = JsonConvert.SerializeObject

               (c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });

我们会得到一个异常:


检测到类型为“Program+JsonTestClass”的属性“test”的自引用循环。小路 ''。


但如果我们这样做,就没有错误:


JsonTestClass c = new JsonTestClass();

c.Name = "test";

c.Test = new JsonTestClass();


string json = JsonConvert.SerializeObject

       (c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });


查看完整回答
反对 回复 2021-11-14
  • 1 回答
  • 0 关注
  • 125 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信