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

如何用Newtonsoft.Json动态反序列化带$type的递归子类型?

递归带$type标记的JSON反序列化问题解决

问题现状

反序列化带$type标记的递归SDF对象树时,顶层对象可正常实例化,但子对象(如SmoothUnion的one、two属性)始终为null,对象树深度超过2层时问题同样存在。

核心原因

  1. 类成员访问性限制:当前SmoothUnion和Sphere类中的字段均为私有(private),Json.NET默认仅序列化/反序列化公共成员,无法对私有字段赋值,导致子对象无法被实例化。
  2. JSON中$type字段的多余空格(如"Sd.SmoothUnion, Assembly-CSharp"中的双空格)可能影响类型解析,虽Json.NET有容错性,但建议统一格式为单空格分隔类型名与程序集名。

解决方案

方案1:改为公共属性(推荐,符合C#封装规范)

将类中的私有字段改为公共属性,若属性名与JSON键名不一致,可通过[JsonProperty]特性指定映射关系:

修改后的SmoothUnion类:

namespace Sd
{
    public class SmoothUnion : SDFObject
    {
        [JsonProperty("one")]
        public SDFObject One { get; set; }
        
        [JsonProperty("two")]
        public SDFObject Two { get; set; }
        
        [JsonProperty("smooth")]
        public float Smooth { get; set; }
        
        public string getFunction()
        {
            return "This is a Smooth Union!";
        }
    }
}

修改后的Sphere类:

namespace Sd
{
    public class Sphere : SDFObject
    {
        [JsonProperty("offset")]
        public List<int> Offset { get; set; }
        
        [JsonProperty("rotation")]
        public List<int> Rotation { get; set; }
        
        [JsonProperty("radius")]
        public int Radius { get; set; }
        
        public string getFunction()
        {
            return "This is a Sphere!";
        }
    }
}

保持原反序列化配置即可:

object o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All,
    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
});
SDFObject s = (SDFObject)o;

方案2:配置Json.NET允许访问私有成员(不推荐,破坏封装)

若无法修改类成员访问级别,可通过自定义ContractResolver让Json.NET解析私有字段:

object o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All,
    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead,
    ContractResolver = new DefaultContractResolver
    {
        DefaultMembersSearchFlags = System.Reflection.BindingFlags.Instance 
            | System.Reflection.BindingFlags.Public 
            | System.Reflection.BindingFlags.NonPublic
    }
});
SDFObject s = (SDFObject)o;

验证效果

修改后重新反序列化目标JSON,SmoothUnion的one、two子对象将正确实例化,递归层级的对象也能正常解析。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:02:45