JSON .Net在反序列化时不尊重PreserveReferencesHandling

我有双重链接列表,我试图反序列化。

我的场景与此SO: 与JSON的双重链接列表密切相关

我有以下JSON设置:

_jsonSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto, ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, PreserveReferencesHandling = PreserveReferencesHandling.Objects, ObjectCreationHandling = ObjectCreationHandling.Auto }; 

当我查看序列化输出时,它看起来是正确的,并且节点之间的引用被正确表示。

反序列化数据时,Child对象中的Parent属性为null,即使它们正确填充了$ ref。

下面是JSON的示例(为了便于阅读而修剪)

在输入这个问题的过程中 – 我可能已经看到了麻烦的根源……

“Children”数组属性中的对象没有$ type属性。

这可能是因为Children和Parent属性属于通用类型T.

请注意,序列化的实际类型是TemplateDataLinkedListBase的派生类

 public class TemplateDataQueryElement : TemplateDataLinkedListBase 

这是基类的摘录:

 public class TemplateDataLinkedListBase where T : TemplateDataLinkedListBase { [JsonProperty(TypeNameHandling = TypeNameHandling.Objects)] public T Parent { get; set; } [JsonProperty(TypeNameHandling=TypeNameHandling.Objects)] public List Children { get; set; } } 

如何以这样的方式反序列化此JSON,即Parent属性不为null并包含对父对象的引用?

  { "$id": "9", "$type": "Contracts.Models.TemplateDataQueryElement, Contracts", "Query": null, "Parent": null, "Children": [ { "$id": "11", "Query": null, "Parent": { "$ref": "9" }, "Children": [ { "$id": "13", "Query": null, "Parent": { "$ref": "11" }, "Children": [], "EntityName": "Widgets", "Fields": [ "Id" ], "Key": "" }, 

以下是相关代码的PasteBin链接:

http://pastebin.com/i1jxVGG3 http://pastebin.com/T1xqEWW2 http://pastebin.com/ha42SeF7 http://pastebin.com/cezwZqx6 http://pastebin.com/uFbTbUZe http:// pastebin .COM / sRhNQgzh

这是我尝试和工作的好:

课程

 public class TemplateDataLinkedListBase where T : TemplateDataLinkedListBase { [JsonProperty(TypeNameHandling = TypeNameHandling.Objects)] public T Parent { get; set; } [JsonProperty(TypeNameHandling = TypeNameHandling.Objects)] public List Children { get; set; } } public class TemplateDataQueryElement : TemplateDataLinkedListBase { public string Query { get; set; } public TemplateDataQueryElement() { Children = new List(); } } 

初始化

 var childLowest = new TemplateDataQueryElement { Query = "Lowest" }; var childMiddle = new TemplateDataQueryElement { Query = "Middle", Children = new List { childLowest } }; childLowest.Parent = childMiddle; var parent = new TemplateDataQueryElement { Query = "Parent", Children = new List { childMiddle } }; childMiddle.Parent = parent; 

序列化设置

 var _jsonSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto, ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, PreserveReferencesHandling = PreserveReferencesHandling.Objects, ObjectCreationHandling = ObjectCreationHandling.Auto }; 

序列化

 var serializedStr = JsonConvert.SerializeObject(parent, Formatting.Indented, _jsonSettings); 

序列化的json看起来像这样:

 { "$id": "1", "Query": "Parent", "Parent": null, "Children": [ { "$id": "2", "Query": "Middle", "Parent": { "$ref": "1" }, "Children": [ { "$id": "3", "Query": "Lowest", "Parent": { "$ref": "2" }, "Children": [] } ] } ] } 

反序列化

 var deserializedStructure = JsonConvert.DeserializeObject(serializedStr, _jsonSettings); 

deserializedStructure中的引用被正确保留。

演示 https://dotnetfiddle.net/j1Qhu6

更新1

我的示例工作的原因,以及您在其他链接中发布的代码不是因为我的类包含默认构造函数,而您的类不包含。 分析您的类,向它们添加默认构造函数,它不会破坏function,并且在正确初始化Parent属性的情况下反序列化将成功。 所以你基本上需要做的是为这两个类添加一个默认构造函数:

 public class TemplateDataLinkedListBase where T : TemplateDataLinkedListBase { [JsonProperty(TypeNameHandling = TypeNameHandling.Objects)] public T Parent { get; set; } [JsonProperty(TypeNameHandling=TypeNameHandling.Objects)] public List Children { get; set; } public string EntityName { get; set; } public HashSet Fields { get; set; } public string Key { get { return getKey(); } } public TemplateDataLinkedListBase() { Children = new List(); Fields = new HashSet(); } public TemplateDataLinkedListBase(string entityName) { EntityName = entityName; Children = new List(); Fields = new HashSet(); } private string getKey() { List keys = new List(); keys.Add(this.EntityName); getParentKeys(ref keys, this); keys.Reverse(); return string.Join(".", keys); } private void getParentKeys(ref List keys, TemplateDataLinkedListBase element) { if (element.Parent != null) { keys.Add(element.Parent.EntityName); getParentKeys(ref keys, element.Parent); } } public T AddChild(T child) { child.Parent = (T)this; Children.Add(child); return (T)this; } public T AddChildren(List children) { foreach (var child in children) { child.Parent = (T)this; } Children.AddRange(children); return (T)this; } public void AddFields(IEnumerable fields) { foreach (var field in fields) this.Fields.Add(field); } public TemplateDataLinkedListBase Find(string searchkey) { if (this.Key == searchkey) { return this; } else { foreach (var child in Children) { if (child.Key == searchkey) { return child; } else { var childResult = child.Find(searchkey); if (childResult != null) return childResult; } } } return null; } } public class TemplateDataQueryElement : TemplateDataLinkedListBase, ITemplateDataQueryElement { public string TemplateModelName { get; set; } public string RecordId { get; set; } public string ParentForeignKeyName { get; set; } public string Query { get; set; } public dynamic ObjectData { get; set; } public ITemplateDataParseResult ParseResult { get; set; } public TemplateDataQueryElement() : base() { Fields.Add("Id"); //Always retrieve Id's ObjectData = new ExpandoObject(); } public TemplateDataQueryElement(string entityName) : base(entityName) { Fields.Add("Id"); //Always retrieve Id's ObjectData = new ExpandoObject(); } public override string ToString() { return string.Format("{0}: {1}", EntityName, Query); } } 

您通过构造函数设置的EntityName属性将被正确反序列化,因为它是一个公共属性。