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
属性将被正确反序列化,因为它是一个公共属性。