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

C# 使用JsonConverter存储/检索子-父关系,c#,json,json.net,C#,Json,Json.net,我有一个JSON结构(包括POCO类),子对象数组如下: "Object": [ { "Name": "TestA", "ChildObjects": [ { "Name": "TestB" "ChildObjects": [ { "Name": "TestC" ...

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

"Object": [ { "Name": "TestA", "ChildObjects": [ { "Name": "TestB" "ChildObjects": [ { "Name": "TestC" ... } ] } ] “对象”:[ { “姓名”:“遗嘱”, “儿童对象”:[ { “名称”:“TestB” “儿童对象”:[ { “名称”:“TestC” ... } ] } ] 反序列化时,我希望保留对父级的引用 我刚刚创建的对象

但我必须在填充子对象之前获得此引用。(在填充子对象时,我必须访问父对象结构/引用)

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

您不需要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; }
    }
公共类OstacolisRuntime
{
public int codiceostatolo{get;set;}
公共int TipoOstacolo{get;set;}
公共int Tipologia{get;set;}
公共字符串Nome{get;set;}
公共双PosizioneX{get;set;}
公共双位置{get;set;}
公共双PosizioneZ{get;set;}
公共双AngoloX{get;set;}
公共双AngoloY{get;set;}
公共双AngoloZ{get;set;}
公共双ScalaX{get;set;}
公共双尺度{get;set;}
公共双标量{get;set;}
公共列表子目录{get;set;}//sub
}
公共类Subogetto
{
公共字符串Immagine{get;set;}
公共int Tipologia{get;set;}
公共字符串Nome{get;set;}
公共双PosizioneX{get;set;}
公共双位置{get;set;}
公共双PosizioneZ{get;set;}
公共双AngoloX{get;set;}
公共双AngoloY{get;set;}
公共双AngoloZ{get;set;}
公共双ScalaX{get;set;}
公共双尺度{get;set;}
公共双标量{get;set;}
公共列表子目录{get;set;}//递归relaship
}
公共类根对象
{
公共列表OstacolisRuntime{get;set;}
}
反序列化json:

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

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

给定父对象和子对象的层次结构,如何确保在将父对象添加到其父对象时,自动正确设置对父对象的子对象返回引用

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

实现这一点的一种方法是定义的自定义子类,该子类自动设置和清除父反向引用

首先,定义以下接口和集合:

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);
    }
}
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);
    }
}
注:

  • MyObject
    中的集合
    IList ChildObjects
    是get only。Json.NET(以及
    XmlSerializer
    )可以成功地反序列化一个get only预分配的集合

  • 方法
    shouldSerializedChildObjects()
    是可选的,可防止对空
    ChildObjects[]
    数组值进行序列化

  • 由于它本身是
    Collection
    的子类,因此如果在添加或删除项目时需要通知,可以选择它作为
    ChildCollection
    的基类

  • Parent
    属性标记为,以防止其序列化


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

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

让我们以设置
RootObject
名为
MyObject
的项的父对象为例:

{
    "Object":[
        {
            "Name": "TestA"
        }
    ]
}
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; }
}
定义集合:

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);
    }
}
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);
    }
}

您是否尝试将设置设置为
Objects
?如果这样做,您不需要转换器;引用将通过特殊的
$id
$ref
元属性保留在JSON中。@BrianRogers,我考虑过在“对象类”中添加一个“父对象”属性。这样我就可以获得对父节点的引用。您刚才告诉我的引用内容是否适合此用途?(如果它可以用作对JSON文件上父节点的引用)是的,您的子对象可以引用父对象,反之亦然,如果您在序列化和反序列化时都使用该设置,则应该可以使用该设置。您是否可以将您的问题共享(理想情况下简化)类型的版本——即a?我不清楚哪些类型对应于上面的JSON,哪些类型在创建过程中需要父节点。@dbc,它是doneM.Hassan。我已经有了这些类。我必须在反序列化时找到获得这种关系的方法。子节点必须能够在反序列化时知道父节点。