问题
I have a JSON structure (including POCO classes) with child-objects arrays like this:
"Object": [ { "Name": "TestA", "ChildObjects": [ { "Name": "TestB" "ChildObjects": [ { "Name": "TestC" ... } ] } ]
When deserializing, I would like to keep a reference to the parent object I've just created.
But I must get this reference before populating the child-object.(On the moment that I populate the child-object I must have the parent-object structure/reference accessible).
I've tried using a custom JsonConverter, but I could not find a way to store or retrieve this relationship.
回答1:
Rather than defining this as a serialization problem (how to serialize and deserialize a back-reference to a parent), it might make sense to define this as a class design problem, namely
Given a hierarchy of parents and children, how to ensure that child back-references to parents are automatically set correctly when adding them to their parents?
Once the problem is defined in this way and solved, correctness should be assured both during deserialization and during programmatic data creation, since the parent back-reference would never need to be serialized or deserialized.
One way to accomplish this would be to define a custom subclass of Collection<T> that automatically sets and clears parent back references.
First, define the following interface and collection:
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);
}
}
Then define your MyObject
and RootObject
types as follows:
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; }
}
Notes:
The collection
IList<MyObject> ChildObjects
inMyObject
is get-only. Json.NET (andXmlSerializer
for that matter) can successfully deserialize a get-only, pre-allocated collection.The method
ShouldSerializeChildObjects()
is optional and prevents serialization of emptyChildObjects []
array values.Since ObservableCollection<T> is itself a subclass of
Collection<T>
, you could chose it as the base class forChildCollection<TParent, TChild>
if you require notifications when items are added or removed.The
Parent
property is marked with [JsonIgnore] to prevent its serialization.
Sample fiddle including some basic unit tests.
回答2:
You needn't JsonConverter.
You can create POCO classes that represent your json, as given below:
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; }
}
Deserialize you json:
var o= JsonConvert.DeserializeObject<RootObject>(json);
You can check complete source code
来源:https://stackoverflow.com/questions/46774119/store-retrieve-child-parent-relationship-with-jsonconverter