【问题标题】:Serialize Circular Reference with Newtonsoft Json使用 Newtonsoft Json 序列化循环引用
【发布时间】:2019-07-19 13:17:38
【问题描述】:

我正在尝试序列化和反序列化的实体:

public class Car
{
    public string Model { get; set; }
    public DateTime Year { get; set; }
    public List<string> Features { get; set; }

    private Car _car;
    public Car Car1
    {
        get
        {
            return _car != null ? _car : new Car();
        }
        set
        {
            _car = value;
        }
    }
}

我正在使用 Newtonsoft Json 库对上述实体进行序列化和反序列化。 在序列化和反序列化此实体时,我不能忽略任何属性。

虽然直接序​​列化实体会引发 StackOverflow 异常。

JsonConvert.SerializeObject(car)

它提到的大多数其他地方都提到了使用以下解决方案,但没有一个对我有用。

var _jsonSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Auto,
    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    ObjectCreationHandling = ObjectCreationHandling.Auto
};

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

settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;

var serialize = JsonConvert.SerializeObject(car, _jsonSettings);

or

var serialize = JsonConvert.SerializeObject(car, settings);

我知道这个属性有问题

private Car _car;
    public Car Car1
    {
        get
        {
            return _car != null ? _car : new Car();
        }
        set
        {
            _car = value;
        }
    }

但我现在无法摆脱它。

修改后的问题:

public interface IEntity
    {
        int Id { get; set; }
    }
    public class Base1 : IEntity
    {
        public virtual int Id { get; set; }
    }
public class Car : Base1
    {//same properties as defined above in above Car class + below property
        private int _carId;
        public int CarId
        {
            get { return _carId; }
            set { _carId = value; Id = value; }
        }
    }

            var car = new Car();
            car.Model = "Amaze";
            car.Year = new DateTime(2016, 1, 1);
            car.Features = new List<string> { "Light", "1", "2" };
            car.CarId = 1;

这里基类的 ID 总是为零,派生的总是设置非零值。 是否可以编写自定义转换器(通过检查属性 ID 的值是否为零,然后不要进一步序列化该属性(Car1 属性)?) 任何建议,如何实现这一目标?

【问题讨论】:

  • 可能是错字,但在上面的代码中您使用的是 _jsonSettings,设置变量具有循环处理标志。我相信这就是你所追求的。换句话说,尝试更改为: var serialize = JsonConvert.SerializeObject(car, settings);
  • 所以你的 Car 有一个 Car1,有一个 Car1,有一个 Car1,那个......你确定你的班级做你想让它做的事吗?

标签: c# serialization json.net deserialization


【解决方案1】:

您遇到此问题的原因有两个:

return _car != null ? _car : new Car();

如果_car 的值为null,则每次都会返回一个新实例,这会将序列化程序发送到导致溢出的无限遍历。

您需要重新考虑您的设计。您应该将新实例分配给内部变量,否则您将丢失引用并继续拥有null

public Car Car1
{
    get
    {
        if(_car == null)
            _car = new Car();
        return _car;
    }
    set
    {
        _car = value;
    }
}

然而,这种自动初始化将继续成为问题,因为总会有一个值需要序列化。如果不存在任何对象,则该值应为 null,这将允许序列化程序完成其工作并到达对象图的末尾。

【讨论】:

  • 是的。我知道问题出在哪里。但是真的很难重新考虑这个设计并使其正确。这就是为什么我问是否有任何解决方法可以让它发挥作用。
  • @Gopu_Tunas:想一想。这就是序列化程序正在做的事情,因为属性总是有一个值。如果序列化程序在某个时候停止,您将丢失信息。如果没有,它将永远存在:(伪代码)Serialize(car) =&gt; SerializeInternalProperty(car); =&gt; SerializeInternalProperty(car); =&gt; SerializeInternalProperty(car); =&gt; SerializeInternalProperty(car); =&gt; SerializeInternalProperty(car);... eternity。你到底要如何“解决”这个问题?
  • @Gopu_Tunas 我不知道为什么你会想要你正在创建的废弃汽车场景,但是如果你愿意为序列化程序设置 MaxDepth 设置,你可以让序列化程序工作.
  • @peter.edwards:正如我所提到的,他会丢失信息并首先破坏序列化的目的,但你是对的。
  • @Gopu_Tunas:你误解了序列化。请再次阅读我的回答。您的修改版本仍然存在相同的问题,因为您正在尝试选择性地序列化内容。你需要重新考虑你的设计。序列化旨在表示您的对象图,因此使用自定义序列化程序选择性地遗漏内容是没有意义的。整个想法是您希望能够物化支持完全相同的[图形]对象[s]。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多