JsonSerializer循环引用问题:标记忽略属性仍报错如何解决?
解决System.Text.Json序列化双向链表时的循环引用问题
你遇到的核心问题是**[ScriptIgnore]不是System.Text.Json识别的特性**,而且子类重写父类属性时,父类的忽略标记不会自动继承,导致序列化器仍然尝试访问双向链表的关联属性,触发循环引用检测。
直接有效的解决方案:使用System.Text.Json专属的[JsonIgnore]特性
System.Text.Json只认自己的[JsonIgnore]特性(来自System.Text.Json.Serialization命名空间),之前用的[ScriptIgnore]是针对Newtonsoft.Json或旧版ASP.NET的,完全不起作用。同时要注意:子类重写父类的属性时,必须在重写的属性上也添加[JsonIgnore],父类的标记不会自动传递。
修改后的代码示例:
// 先引入命名空间 using System.Text.Json.Serialization; public class BObject : Panel, ISerializable, ICloneable { public eObjectType typObject; ... [JsonIgnore] // 替换原有的[ScriptIgnore] public virtual BObject pSuccessor { get { return null; } set { } } [JsonIgnore] // 替换原有的[ScriptIgnore] public virtual BObject pPredecessor { get { return null; } set { } } ... } [Serializable] public partial class DvObject : BObject, ISerializable { [NonSerialized] protected DvObject pPrevious; [NonSerialized] protected DvObject pNext; ... [JsonIgnore] public override BObject pSuccessor { get { return pNext; } set { pNext = (DvObject)value; } // 原代码的(RvmComponent)应为笔误,改为DvObject } [JsonIgnore] // 必须添加!父类的[JsonIgnore]不会继承到重写的属性上 public override BObject pPredecessor { get { return pPrevious; } set { ... pPrevious = (DvObject)value; ... } } }
备选方案:通过JsonSerializerOptions全局配置(无需修改类)
如果无法修改类的定义,可以在序列化时通过配置忽略指定属性,或者开启自动忽略循环引用:
var options = new JsonSerializerOptions { // 方案1:自动忽略引发循环引用的属性 IgnorePropertiesWithReferenceCycles = true, // 方案2:精准忽略指定属性(更可靠) TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { if (typeInfo.Type == typeof(BObject) || typeInfo.Type.IsSubclassOf(typeof(BObject))) { // 移除要忽略的属性 var propToRemove = typeInfo.Properties.FirstOrDefault(p => p.Name is "pSuccessor" or "pPredecessor"); if (propToRemove != null) { typeInfo.Properties.Remove(propToRemove); } } } } } }; // 修正序列化代码:原代码循环中序列化整个集合,应改为序列化单个对象 foreach (BObject obj in lobj) { String jsonObj = JsonSerializer.Serialize(obj, options); }
额外提示
[NonSerialized]只对字段生效,对属性完全没有影响,标记在pPrevious、pNext字段上没用,可以删掉。- 原序列化代码中
JsonSerializer.Serialize(lobj, options)是序列化整个集合,若你本意是序列化单个对象,需改为Serialize(obj, options),避免重复序列化整个集合。
内容的提问来源于stack exchange,提问作者UHM
相关产品推荐
相关产品推荐

