猿问

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

我在使用 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 异常:

RISEBY
浏览 126回答 1
1回答

慕的地8271018

为什么 JsonConvert.SerializeObject 会调用该object.Equals方法?因为当你使用 时JsonConvert.SerializeObject,有一个方法CheckForCircularReference被调用来检查一个属性是否重新引用了你自己的对象,导致无限循环。&nbsp;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)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? _serializeStack.Contains(value, Serializer._equalityComparer)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : _serializeStack.Contains(value);解释_serializeStack 是当前正在序列化的对象列表。该List<T>.Contains方法检查当前属性是否包含在集合中。List<T>.Containsuses EqualityComparer<T>.Default,IEquatable<T>如果类型实现它,则依次使用,object.Equals否则使用。该object value参数是您当前的Property对象。下面是一个自引用循环的例子:public class JsonTestClass{&nbsp; &nbsp; public string Name { get; set; }&nbsp; &nbsp; public List<int> MyIntList { get; set; }&nbsp; &nbsp; public JsonTestClass Test{get;set;}&nbsp; &nbsp; public override bool Equals(object obj)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (obj == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; &nbsp; &nbsp; JsonTestClass jtc = (JsonTestClass)obj;&nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp;}}JsonTestClass c = new JsonTestClass();c.Name = "test";c.Test = c;string json = JsonConvert.SerializeObject&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });我们会得到一个异常:检测到类型为“Program+JsonTestClass”的属性“test”的自引用循环。小路 ''。但如果我们这样做,就没有错误:JsonTestClass c = new JsonTestClass();c.Name = "test";c.Test = new JsonTestClass();string json = JsonConvert.SerializeObject&nbsp; &nbsp; &nbsp; &nbsp;(c, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
随时随地看视频慕课网APP
我要回答