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

如何使用JSON.NET反序列化时为嵌套类传递外部类引用?

如何用JSON.NET反序列化嵌套类并让内部类获取外部类引用?

这个问题我之前也碰到过,JSON.NET默认反序列化的时候确实不会自动处理这种嵌套类的外部引用,不过有两种比较实用的解决办法,我给你详细说下:

首先先修正下你给出的类结构(原代码里的_outerRef没声明类型,而且实际场景是List<inner>成员,另外JSON.NET反序列化需要无参构造):

public class outer 
{ 
    public int id; 
    public List<inner> inners; // 实际场景的List类型成员

    public class inner 
    { 
        private outer _outerRef; 
        public inner() {} // 必须添加无参构造,否则JSON.NET无法直接反序列化
        public inner(outer outerRef) { _outerRef = outerRef; } 
        public int id; 
        // 用表达式体写法更简洁
        public string name => $"{id}.{_outerRef.id}"; 
    } 
}

方法一:利用JSON.NET的OnDeserialized回调(最简单)

JSON.NET提供了序列化/反序列化的生命周期回调,我们可以在outer类里加一个反序列化完成后的方法,给每个inner实例设置外部引用:

只需要给outer类添加回调方法,同时给inner类加一个设置引用的方法:

public class outer 
{ 
    public int id; 
    public List<inner> inners; 

    public class inner 
    { 
        private outer _outerRef; 
        public inner() {}
        public inner(outer outerRef) { _outerRef = outerRef; } 
        public int id; 
        public string name => $"{id}.{_outerRef.id}"; 

        // 给内部类添加设置外部引用的方法
        public void SetOuterRef(outer outer)
        {
            _outerRef = outer;
        }
    } 

    // 标记这个方法在反序列化完成后触发
    [Newtonsoft.Json.OnDeserialized]
    private void OnDeserialized(Newtonsoft.Json.Serialization.StreamingContext context)
    {
        // 遍历所有inner实例,设置外部引用
        if (inners != null)
        {
            foreach(var innerItem in inners)
            {
                innerItem.SetOuterRef(this);
            }
        }
    }
}

然后反序列化的时候直接用常规写法就行:

// 示例JSON字符串
var json = "{\"id\":5, \"inners\":[{\"id\":7}, {\"id\":8}]}";
var outerInstance = Newtonsoft.Json.JsonConvert.DeserializeObject<outer>(json);
// 此时每个inner的name属性都能正常计算,比如第一个inner的name是"7.5"

方法二:自定义JsonConverter(更灵活)

如果你需要在反序列化inner的过程中就控制引用设置,或者有更复杂的逻辑,可以自定义一个转换器来处理outer类:

public class OuterConverter : Newtonsoft.Json.JsonConverter<outer>
{
    public override outer ReadJson(JsonReader reader, Type objectType, outer existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 先把JSON加载成JObject,方便手动处理各个属性
        var jsonObj = JObject.Load(reader);
        
        // 创建outer实例
        var outerInstance = new outer();
        // 反序列化outer的id属性
        outerInstance.id = jsonObj["id"].Value<int>();
        // 反序列化inners列表(此时inner实例还没有外部引用)
        outerInstance.inners = jsonObj["inners"].ToObject<List<outer.inner>>(serializer);
        
        // 给每个inner设置外部引用
        foreach(var innerItem in outerInstance.inners)
        {
            innerItem.SetOuterRef(outerInstance);
        }
        
        return outerInstance;
    }

    public override void WriteJson(JsonWriter writer, outer value, JsonSerializer serializer)
    {
        // 序列化的时候用默认逻辑即可
        serializer.Serialize(writer, value);
    }
}

使用的时候需要把转换器加入序列化设置:

var jsonSettings = new Newtonsoft.Json.JsonSerializerSettings();
jsonSettings.Converters.Add(new OuterConverter());

var outerInstance = Newtonsoft.Json.JsonConvert.DeserializeObject<outer>(json, jsonSettings);

注意事项

  • 一定要给inner类加无参构造函数,JSON.NET默认会用无参构造创建实例,除非你在转换器里手动调用带参构造(但那样会增加复杂度)。
  • 如果不想公开SetOuterRef方法,可以把它设为internal,然后在项目属性里设置InternalsVisibleTo("Newtonsoft.Json"),或者用反射设置私有字段(不推荐,反射性能差且不利于维护)。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:46:24