Подтвердить что ты не робот

Как передать параметр в десериализацию конструктора json

У меня есть небольшая проблема с передачей некоторого родительского экземпляра конструктору при десериализации объекта с Newtonsoft.Json.

Предположим, что у меня есть следующие классы

public class A
{
    public string Str1 { get; set; }

    public IList<B> Bs { get; set; }
}

public class B
{
    public B(A a)
    {
        // a should not be null!
        Console.WriteLine(a.Str)
    }
}

И теперь я serailze и десериализую объект a следующим образом:

A a = new A()
a.Bs = new List<B>()
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));

var json = JsonConvert.SerializeObject(a);

// Here i need to call the constructor of B when creating new instances
var newA = JsonConvert.DeserializeObject<A>(json);

Проблема заключается в том, что при десериализации объекта null передается конструктору B. Кто-нибудь решил эту проблему/проблему раньше?

Большое спасибо!

4b9b3361

Ответ 1

В вашем вопросе и комментариях вы сказали, что класс B не имеет общедоступного свойства для A. Итак, когда вы сериализуете B, в JSON будет записано no A, потому что Json.Net только сериализует общедоступную информацию по умолчанию. Поэтому при десериализации данных для воссоздания B не будет достаточно информации, поскольку в JSON нет A. Итак, первый шаг делает ссылку B на A видимой для Json.Net. Если вы не хотите публиковать его, это нормально, но вам, по крайней мере, нужно будет пометить участника атрибутом [JsonProperty], чтобы Json.Net мог "видеть" его.

public class B
{
    [JsonProperty]
    private A a;

    public B(A a)
    {
        this.a = a;  // be sure to set the A member in your constructor
    }
}

Теперь, если вы выполните вышеописанное, вы столкнетесь с второй проблемой: ваша структура класса имеет опорный цикл (A имеет список B, каждый из которых ссылается на A), и сериализатор будет бросать исключение по умолчанию в этом случае. Решение состоит в том, чтобы установить для параметра serializer PreserveReferencesHandling значение Objects (по умолчанию это None). Это не только позволит сериализатору обрабатывать опорные циклы во время сериализации, но также сохранит исходные ссылки во время десериализации, так что все B будут ссылаться на один и тот же экземпляр A. (Это выполняется с помощью специальных свойств $id и $ref, которые записываются в JSON.)

JsonSerializerSettings settings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};

var json = JsonConvert.SerializeObject(a, settings);

var newA = JsonConvert.DeserializeObject<A>(json, settings);

Рабочий пример: https://dotnetfiddle.net/N0FUID