2

I'm seeing some weird behavior serializing with Json.NET v6.0.5 for objects that override the Equals method and have reference type properties, aside from string.

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
{
}

Then I serialize it.

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

I can see that it calls TestObject.Equals(object obj) three times and passes in not the TestObject, but the CustomTypePropety object, then the ListProperty and then the ListCustomProperty. In my case this causes an InvalidCastException because TestObject tries to cast the obj parameter to a TestObject. I cannot change this in the real-world scenario because the the type is in a third party library.

Is this a bug in Json.NET or am I doing something wrong? I've been digging for a while and cannot find any resolution. Thanks for the help.

EDIT

I just upgraded to Json.NET 6.0.6 and saw the same behavior.

r2_118
  • 640
  • 1
  • 9
  • 25

1 Answers1

2

If you are implementing an override for bool Equals(object obj) then you need to handle any type that might be passed to you. You cannot make the assumption that callers will always pass the type you are expecting. The usual solution is to do a simple type check before you cast, like this:

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);
}

If it is a third party library that throws an InvalidCastException in the Equals method, that is definitely a bug. I would contact the author and request that they fix it.

As for why Json.Net calls Equals during serialization on objects of different types, this is done to check for reference loops. See Why does Json.Net call the Equals method on my objects when serializing? for more details.

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • I dont think you should feel stupid at all @r2_118 =) I think this is a completely weird behavior and should never happen. Passing in an object to an equals method that is of a different type, is very strange. I am having the same problem now, which causes a lot of headaches. – Ted Aug 03 '18 at 08:50
  • 1
    I got an answer when I asked why here: https://stackoverflow.com/questions/51669072/json-net-newtonsoft-using-jsonconvert-serializeobject-results-in-weird-equal – Ted Aug 03 '18 at 11:00