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


    “对象”:[
    {
        “名称”:“ TestA”,
        “ ChildObjects”:[
        {
            “名称”:“ TestB”
            “ ChildObjects”:[
                {
                    “名称”:“ TestC”
                    ...
                }
            ]
        }
    ]



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

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

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

最佳答案

与其将其定义为序列化问题(如何序列化和反序列化对父级的反向引用),不如将其定义为类设计问题,即


  给定父级和子级的层次结构,如何确保在将父级添加到父级时自动正确设置对父级的子级反向引用?


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

实现此目的的一种方法是定义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是只读的。 Json.NET(和XmlSerializer可以成功地反序列化仅获取的,预分配的集合)。
方法ShouldSerializeChildObjects()是可选的,它可以防止对空的ChildObjects []数组值进行序列化。
由于ObservableCollection<T>本身是Collection<T>的子类,因此如果需要在添加或删除项目时进行通知,则可以将其选择为ChildCollection<TParent, TChild>的基类。
Parent属性用[JsonIgnore]标记,以防止其序列化。


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

10-04 14:33