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

Ric*_*eis 4 c# json json.net

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

    “目的”: [
    {
        "名称": "TestA",
        “子对象”:[
        {
            “名称”:“测试B”
            “子对象”:[
                {
                    “名称”:“测试C”
                    ...
                }
            ]
        }
    ]

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

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

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

dbc*_*dbc 5

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

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

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

实现此目的的一种方法是定义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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后定义您的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; }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 收集IList<MyObject> ChildObjectsMyObject为Get-只。Json.NET(以及XmlSerializer就此而言)可以成功地反序列化一个只获取、预先分配的集合。

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

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

  • Parent属性被标记为[JsonIgnore]以防止其序列化。

示例小提琴,包括一些基本的单元测试。