使用JsonConverter存储/检索子父关系

时间:2017-10-16 15:43:27

标签: c# json json.net

我有一个带有子对象数组的JSON结构(包括POCO类),如下所示:


    "Object": [
    {
        "Name": "TestA",
        "ChildObjects": [
        {
            "Name": "TestB"
            "ChildObjects": [
                {
                    "Name": "TestC"
                    ...
                }
            ]
        }
    ]

反序列化时,我想保留对父级的引用 对象我刚刚创建。

但是我必须在填充子对象之前得到这个引用。(在我填充子对象的那一刻,我必须有父对象结构/引用可访问)

我尝试过使用自定义JsonConverter,但是 我找不到存储或检索这种关系的方法。

3 个答案:

答案 0 :(得分:2)

不是将其定义为序列化问题(如何序列化和反序列化对父项的反向引用),将其定义为类设计问题可能是有意义的,即

  

鉴于父母和子女的等级,如何确保在向父母添加父母时,自动正确设置对父母的反对引用?

一旦问题以这种方式定义并解决,在反序列化期间和程序化数据创建期间都应该确保正确性,因为父反向引用永远不需要被序列化或反序列化。

实现此目的的一种方法是定义Collection<T>的自定义子类,自动设置和清除父后引用。

首先,定义以下界面和集合:

public interface IHasParent<TParent> where TParent : class
{
    TParent Parent { get; }

    void OnParentChanging(TParent newParent);
}

public class ChildCollection<TParent, TChild> : Collection<TChild>
    where TChild : IHasParent<TParent>
    where TParent : class
{
    readonly TParent parent;

    public ChildCollection(TParent parent)
    {
        this.parent = parent;
    }

    protected override void ClearItems()
    {
        foreach (var item in this)
        {
            if (item != null)
                item.OnParentChanging(null);
        }
        base.ClearItems();
    }

    protected override void InsertItem(int index, TChild item)
    {
        if (item != null)
            item.OnParentChanging(parent);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        var item = this[index];
        if (item != null)
            item.OnParentChanging(null);
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, TChild item)
    {
        var oldItem = this[index];
        if (oldItem != null)
            oldItem.OnParentChanging(null);
        if (item != null)
            item.OnParentChanging(parent);
        base.SetItem(index, item);
    }
}

然后按如下方式定义您的MyObjectRootObject类型:

public class MyObject : IHasParent<MyObject>
{
    readonly ChildCollection<MyObject, MyObject> childObjects;

    public MyObject() { this.childObjects = new ChildCollection<MyObject, MyObject>(this); }

    public string Name { get; set; }

    public IList<MyObject> ChildObjects { get { return childObjects; } }

    #region IHasParent<MyObject> Members

    [JsonIgnore]
    public MyObject Parent { get; private set; }

    public void OnParentChanging(MyObject newParent)
    {
        Parent = newParent;
    }

    #endregion

    // Added to suppress serialization of empty ChildObjects collections to JSON.
    public bool ShouldSerializeChildObjects() { return childObjects.Count > 0; }
}

public class RootObject
{
    public RootObject() { this.Object = new List<MyObject>(); }

    public List<MyObject> Object { get; set; }
}

注意:

  • IList<MyObject> ChildObjects中的集合MyObject是get-only。 Json.NET(以及XmlSerializer就此而言)可以成功地反序列化一个只用于预分配的集合。

  • 方法ShouldSerializeChildObjects()是可选的,可防止序列化空的ChildObjects []数组值。

  • 由于ObservableCollection<T>本身是Collection<T>的子类,如果在添加或删除项目时需要通知,则可以选择它作为ChildCollection<TParent, TChild>的基类。

  • Parent属性标有[JsonIgnore]以阻止其序列化。

示例fiddle包括一些基本的单元测试。

答案 1 :(得分:0)

你不需要JsonConverter。

您可以创建代表您的json的POCO类,如下所示:

    public class OstacolisRuntime
    {
        public int CodiceOstacolo { get; set; }
        public int TipoOstacolo { get; set; }
        public int Tipologia { get; set; }
        public string Nome { get; set; }
        public double PosizioneX { get; set; }
        public double PosizioneY { get; set; }
        public double PosizioneZ { get; set; }
        public double AngoloX { get; set; }
        public double AngoloY { get; set; }
        public double AngoloZ { get; set; }
        public double ScalaX { get; set; }
        public double ScalaY { get; set; }
        public double ScalaZ { get; set; }
        public List<SubOggetto> SubOggettos { get; set; } //sub
    }




    public class SubOggetto
    {
        public string Immagine { get; set; }
        public int Tipologia { get; set; }
        public string Nome { get; set; }
        public double PosizioneX { get; set; }
        public double PosizioneY { get; set; }
        public double PosizioneZ { get; set; }
        public double AngoloX { get; set; }
        public double AngoloY { get; set; }
        public double AngoloZ { get; set; }
        public double ScalaX { get; set; }
        public double ScalaY { get; set; }
        public double ScalaZ { get; set; }
        public List<SubOggetto> SubOggettos { get; set; } //recursive relashioship
    }


    public class RootObject
    {
        public List<OstacolisRuntime> OstacolisRuntime { get; set; }
    }

反序列化你json:

  var o= JsonConvert.DeserializeObject<RootObject>(json);

您可以查看complete source code

答案 2 :(得分:0)

为了更清楚地理解dbc的答案,让我简化一下。

我们以为RootObject的名为MyObject的项目设置父级为例:

{
    "Object":[
        {
            "Name": "TestA"
        }
    ]
}

定义集合:

public class Items : Collection<MyObject>
{
    private RootObject Owner;

    public Items(RootObject owner)
    {
        Owner = owner;
    }

    protected override void InsertItem(int index, MyObject item)
    {
        item.Parent = Owner;
        base.InsertItem(index, item);
    }
}

定义MyObjectRootObject

public class MyObject
{
    [JsonIgnore]
    public RootObject Parent { get; set; }

    public string Name { get; set; }
}

public class RootObject
{
    public RootObject() { ChildObjects = new Items(this); }

    public Items ChildObjects { get; }
}