Newtonsoft.Json - собственный цикл ссылок, но DTO, похоже, не имеет одного

Я создал класс, содержащий другой класс. Newtonsoft говорит мне, что существует цикл саморегуляции, когда на объект вызывается JsonConvert.SerializeObject(translationResponse). После того, как я попробовал разные вещи, я изменил имя пространства имен (которое было "DocumentGenerationParticipant" и создало DocumentGenerationParticipantResult для множественного списка классов, вместо использования сингулярной версии, которая также является DTO для конечной точки/участника. Это сработало, но я не Не понимаю, почему сериализация JSON не будет работать над этим, и я не вижу циркулярной ссылки? Я что-то пропустил?

Program.CS, которая использует ниже DTO:

using ConsoleApp4.DocumentGeneration;
using ConsoleApp4.DocumentGeneration.DocumentGenerationParticipant;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace ConsoleApp4
{
    static class Program
    {
        static void Main(string[] args)
        {
            var list = new List<DocumentGenerationParticipantResponse>()
            {
                new DocumentGenerationParticipantResponse("testName","testEmail","testUri","testRole"),
                new DocumentGenerationParticipantResponse("testName","testEmail","testUri","testRole"),
                new DocumentGenerationParticipantResponse("testName","testEmail","testUri","testRole")
            };
            var response = new DocumentGenerationParticipantsResponse(list);
            var result = JsonConvert.SerializeObject(response);
            Console.WriteLine(result);
        }
    }
}

DocumentGenerationParticipantResponse:

using System.Collections.Generic;

namespace ConsoleApp4.DocumentGeneration
{
    public class DocumentGenerationParticipantResponse
    {
        public string Name { get; }

        public string Email { get; }

        public string AccessUri { get; }

        public string Role { get; }

        public DocumentGenerationParticipantResponse(string name, string email, string accessUri, string role)
        {
            this.Name = name;
            this.Email = email;
            this.AccessUri = accessUri;
            this.Role = role;
        }

        public override bool Equals(object obj)
        {
            if (obj is null)
            {
                return false;
            }

            if (ReferenceEquals(this, obj))
            {
                return true;
            }

            DocumentGenerationParticipantResponse tmp = (DocumentGenerationParticipantResponse)obj;
            return Equals(this.Name, tmp.Name) &&
                   Equals(this.Email, tmp.Email) &&
                   Equals(this.AccessUri, tmp.AccessUri) &&
                   Equals(this.Role, tmp.Role);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                var hashCode = -2099;
                hashCode = hashCode * -2399 + EqualityComparer<string>.Default.GetHashCode(Name);
                hashCode = hashCode * -2399 + EqualityComparer<string>.Default.GetHashCode(Email);
                hashCode = hashCode * -2399 + EqualityComparer<string>.Default.GetHashCode(AccessUri);
                hashCode = hashCode * -2399 + EqualityComparer<string>.Default.GetHashCode(Role);
                return hashCode;
            }
        }
    }
}

DocumentGenerationParticipantsResponse:

using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp4.DocumentGeneration.DocumentGenerationParticipant
{
    public class DocumentGenerationParticipantsResponse
    {
        public List<DocumentGenerationParticipantResponse> Participants { get; }

        public DocumentGenerationParticipantsResponse(List<DocumentGenerationParticipantResponse> participants)
        {
            Participants = participants;
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (!(obj is List<DocumentGenerationParticipantResponse> list))
            {
                return false;
            }

            if (list.Count != this.Participants.Count)
            {
                return false;
            }

            return this.Participants.SequenceEqual(list);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                var hashCode = -2099;
                this.Participants.ForEach(x => hashCode = hashCode * x.GetHashCode());
                return hashCode;
            }
        }
    }
}

Сообщение об ошибке: "Сообщение": "Произошла ошибка.", "ExceptionMessage": "Обнаружен собственный цикл привязки для свойства" Участники "с типом" System.Collections.Generic.List'1 [XXXXXX.AX.Management.Contracts. DocumentGeneration.DocumentGenerationParticipantResponse] '. Путь' '. ",

+1
источник поделиться
1 ответ

Ваша проблема в том, что вы перегрузили DocumentGenerationParticipantsResponse.Equals(object obj) чтобы создать объект типа DocumentGenerationParticipantsResponse равный одному из его собственных свойств:

public class DocumentGenerationParticipantsResponse
{
    public List<DocumentGenerationParticipantResponse> Participants { get; }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }

        if (!(obj is List<DocumentGenerationParticipantResponse> list))
        {
            return false;
        }

        if (list.Count != this.Participants.Count)
        {
            return false;
        }

        return this.Participants.SequenceEqual(list);
    }

    // Remainder snipped

В частности, он будет равен любому List<DocumentGenerationParticipantResponse> с тем же содержимым, что и его собственный список Participants. Это объясняет исключение, которое вы видите. Как объясняется в этом ответе на Почему не ссылается на обнаружение цикла, используйте ссылочное равенство? , Json.NET использует равенство объектов, а не ссылочное равенство при проверке циклических ссылок. Таким образом, при сериализации свойства " Participants Json.NET считает, что он равен родительскому объекту DocumentGenerationParticipantsResponse и выдает исключение, которое вы видите.

Если вы не хотите использовать объект равенство при проверке циклических ссылок, вы можете переопределить JsonSerializerSettings.EqualityComparer и заменить поведение по умолчанию, призывающие object.Equals в обнаружении опорного контура с чем - то еще, например, ReferenceEqualityComparer от этого ответа на IEqualityComparer <T> который использует ReferenceEquals by AnorZaken. Но прежде чем это сделать, вы должны изучить свои методы Equals() чтобы убедиться, что они действительно делают то, что вы хотите, поскольку в этом случае DocumentGenerationParticipantsResponse.Equals() выглядит сломанным, поскольку метод равенства возвращает true для объектов разного типа.

(И, как отмечено в этом ответе Даниэля Гименеса, DocumentGenerationParticipantResponse.Equals() также выглядит сломанным. Среди других проблем он не проверяет, что object obj входящего object obj имеет правильный тип.)

Дальнейшее чтение:

+1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос