Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reference Loop detected erroneously #2627

Closed
pkimike opened this issue Dec 16, 2021 · 2 comments
Closed

Reference Loop detected erroneously #2627

pkimike opened this issue Dec 16, 2021 · 2 comments

Comments

@pkimike
Copy link

pkimike commented Dec 16, 2021

Source/destination types

class RootClass {
    public String Name { get; set; }
    public Int32 Number { get; set; }

    public override Boolean Equals(Object obj) {
        return ReferenceEquals(this, obj) || obj is RootClass other && Equals(other);
    }
    protected Boolean Equals(RootClass other) {
        return String.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase) && Number == other.Number;
    }
    public override Int32 GetHashCode() {
        unchecked {
             return (StringComparer.OrdinalIgnoreCase.GetHashCode(Name) * 397) ^ Number;
        }
    }
}

class ChildContainerClass : RootClass {
    public List<ChildEntryClass> Entries { get; set; } = new List<ChildEntryClass>();
}

class ChildEntryClass : RootClass {
    public String MyProperty { get; set; }
}

Source/destination JSON

Not applicable

Expected behavior

Object serializes properly

Actual behavior

Exception thrown unless ReferenceLoopHandling.Serialize is passed to force

Steps to reproduce

var container = new ChildContainerClass() {
    Name = "My",
    Number = 1
};
var entry = new ChildEntryClass {
    Name = "My",
    Number = 1
};
container.Entries.Add(entry);
Console.WriteLine("Instance Equals  : " + container.Equals(entry)); // returns True, because they equal by implementation
Console.WriteLine("Reference Equals : " + ReferenceEquals(container, entry)); // returns False, because they are different refs
var str = JsonConvert.SerializeObject(container); // will fail with reference loop exception
@elgonzo
Copy link

elgonzo commented Dec 16, 2021

This is not a bug. Using equality comparison for detecting circular references is intended default behavior. For example, see this comment from the author of the library: #401 (comment). (Mostly because this behavior has already been established over a span of numerious library versions across many years before people started asking for a change of this behavior. But at that point breaking compatibility by breaking established default behavior was deemed not acceptable anymore. Unfortunate, but understandable and reasonable...)

Fortunately, you can override this behavior by configuring Newtonsoft.Json's EqualityComparer setting to use object reference equality comparison only:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
    EqualityComparer = ReferenceEqualityComparer.Instance
};

var str = JsonConvert.SerializeObject(container);

@pkimike
Copy link
Author

pkimike commented Dec 16, 2021

Thanks for the clarification.

@pkimike pkimike closed this as completed Dec 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants