You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 19:25:26