JsonConvert.SerializeObject将自定义类型属性传递给父类型Equals(object)方法

时间:2014-10-24 16:20:29

标签: c# serialization json.net

我看到一些奇怪的行为,使用Json.NET v6.0.5为覆盖Equals方法的对象序列化,并且除了字符串之外还有引用类型属性。

public class TestObject
{
    public ChildObject CustomTypeProperty
    {
        get;
        set;
    }

    public List<string> ListProperty
    {
        get;
        set;
    }

    public List<ChildObject> ListCustomProperty
    {
        get;
        set;
    }

    public string StringProperty
    {
        get;
        set;
    }

    public int IntProperty
    {
        get;
        set;
    }

    public override bool Equals(object obj)
    {
        Console.WriteLine(obj.GetType().FullName);
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

public class ChildObject
{
}

然后我序列化它。

var testObj = new TestObject() { CustomTypeProperty = new ChildObject(), IntProperty = 1, ListCustomProperty = new List<ChildObject>(), ListProperty = new List<string>(), StringProperty = "abc" };
var json = JsonConvert.SerializeObject(testObj);

我可以看到它调用TestObject.Equals(object obj)三次并且不传入TestObject,而是传入CustomTypePropety对象,然后是ListProperty,然后是ListCustomProperty。在我的情况下,这会导致InvalidCastException,因为TestObject尝试将obj参数强制转换为TestObject。我无法在现实场景中更改此内容,因为该类型位于第三方库中。

这是Json.NET中的错误还是我做错了什么?我已经挖了一段时间,找不到任何解决方案。谢谢你的帮助。

修改

我刚刚升级到Json.NET 6.0.6并看到了相同的行为。

1 个答案:

答案 0 :(得分:1)

如果要为bool Equals(object obj)实现覆盖,则需要处理可能传递给您的任何类型。您无法假设呼叫者将始终传递您期望的类型。通常的解决方案是在投射之前进行简单的类型检查,如下所示:

public override bool Equals(object obj)
{
    if (obj is TypeYouAreExpecting)
    {
        TypeYouAreExpecting other = (TypeYouAreExpecting) obj;
        bool areEqual = false;

        // implement your equals logic here

        return areEqual;
    }

    return base.Equals(obj);
}

如果它是在InvalidCastException方法中抛出Equals的第三方库,那肯定是一个错误。我会联系作者并要求他们修复它。

至于为什么Json.Net在对不同类型的对象进行序列化时调用Equals,这样做是为了检查引用循环。有关详细信息,请参阅Why does Json.Net call the Equals method on my objects when serializing?