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

如何让JsonConverterAttribute与JsonConvert.Deserialize使用相同命名策略

问题:JsonConverterAttribute与蛇形命名策略兼容问题

场景复现

现有如下待序列化的类:

class Container
{
    [JsonConverter(typeof(PropertyConverter))]
    public PropertyBase SomeProperty { get; set; }
}

使用以下代码进行序列化:

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
};

var serialized = JsonConvert.SerializeObject(
    new Container
    {
        SomeProperty = new PropertyImplementationA
        {
            PropertyA = "some string value"
        }
    }, settings);

但执行反序列化时:

var deserialized = JsonConvert.DeserializeObject<Container>(serialized, settings);

转换器并未生效。排查后发现,移除SnakeCaseNamingStrategy后一切正常,说明标记JsonConverterAttribute的属性,其注册的转换器未使用全局配置的命名策略。

约束条件

  • 临时方案:在序列化器设置中全局注册转换器,但创建设置时无法预知所有需要的转换器,不可行
  • 显式标记[JsonProperty("property_base")]:需要在代码库中大量修改标记,不可行
  • 不能取消SnakeCaseNamingStrategy:这是代码库既定规则,无法修改

核心问题

如何让标记JsonConverterAttribute的属性,与JsonConvert.DeserializeObject传入的JsonSerializerSettings使用相同的命名策略?


解决方案:自定义契约解析器,传递全局命名策略给转换器

问题根源在于,当属性标记JsonConverterAttribute时,Newtonsoft会为该属性创建独立的序列化上下文,未继承全局的命名策略。我们可以通过自定义契约解析器,将全局命名策略传递给转换器。

步骤1:自定义契约解析器

public class SnakeCaseContractResolverWithConverterSupport : DefaultContractResolver
{
    public SnakeCaseContractResolverWithConverterSupport()
    {
        NamingStrategy = new SnakeCaseNamingStrategy();
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        
        // 检测属性是否带有JsonConverterAttribute
        var converterAttr = member.GetCustomAttribute<JsonConverterAttribute>();
        if (converterAttr != null && property.Converter != null)
        {
            // 创建带有全局命名策略的序列化设置
            var converterSettings = new JsonSerializerSettings
            {
                ContractResolver = this,
                NamingStrategy = this.NamingStrategy
            };
            
            // 将设置传递给自定义转换器(需转换器支持接收设置)
            if (property.Converter is PropertyConverter customConverter)
            {
                customConverter.SerializerSettings = converterSettings;
            }
        }
        
        return property;
    }
}

步骤2:修改自定义转换器,支持使用传入的设置

调整PropertyConverter,让它使用传递过来的全局设置进行序列化/反序列化:

public class PropertyConverter : JsonConverter<PropertyBase>
{
    // 接收全局传递的序列化设置
    public JsonSerializerSettings SerializerSettings { get; set; }

    public override void WriteJson(JsonWriter writer, PropertyBase value, JsonSerializer serializer)
    {
        // 使用全局设置序列化,保证命名策略一致
        JsonConvert.SerializeObject(value, writer, SerializerSettings);
    }

    public override PropertyBase ReadJson(JsonReader reader, Type objectType, PropertyBase existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        
        // 根据实际类型标识判断具体实现类,示例中以property_a字段为例
        if (jsonObject.ContainsKey("property_a"))
        {
            // 使用全局设置反序列化
            return jsonObject.ToObject<PropertyImplementationA>(JsonSerializer.Create(SerializerSettings));
        }
        
        // 其他类型判断逻辑...
        return existingValue ?? Activator.CreateInstance(objectType) as PropertyBase;
    }
}

步骤3:使用自定义契约解析器

替换原设置中的契约解析器:

var settings = new JsonSerializerSettings
{
    ContractResolver = new SnakeCaseContractResolverWithConverterSupport()
};

// 序列化和反序列化代码保持不变
var serialized = JsonConvert.SerializeObject(new Container { SomeProperty = new PropertyImplementationA { PropertyA = "some string value" } }, settings);
var deserialized = JsonConvert.DeserializeObject<Container>(serialized, settings);

原理说明

自定义契约解析器在生成属性契约时,会自动检测带有JsonConverterAttribute的属性,并将全局的命名策略通过序列化设置传递给自定义转换器。这样转换器在处理属性时,就会使用和全局一致的蛇形命名策略,解决了两者不兼容的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:32:50