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

C# Newtonsoft.Json如何实现接口与字符串双格式JSON序列化反序列化

解决方案

针对Newtonsoft.Json下IHello类型属性的双格式序列化/反序列化需求,不需要修改原有类结构、不需要向使用者暴露泛型参数,通过自定义JsonConverter即可完全实现需求,对上层使用者无感知。


核心实现:自定义JSON转换器

实现JsonConverter<IHello>类,同时兼容两种格式的序列化、反序列化逻辑:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class HelloInterfaceConverter : JsonConverter<IHello>
{
    private readonly bool _serializeAsString;

    /// <summary>
    /// 初始化转换器
    /// </summary>
    /// <param name="serializeAsString">true时序列化为简化字符串格式,false时保留原有对象格式</param>
    public HelloInterfaceConverter(bool serializeAsString = true)
    {
        _serializeAsString = serializeAsString;
    }

    public override IHello ReadJson(JsonReader reader, Type objectType, IHello existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        // 识别字符串格式:{"Message":"Yo!"}
        if (token.Type == JTokenType.String)
        {
            return new Hello1
            {
                Phrase = token.Value<string>()
            };
        }
        // 识别原有对象格式:{"Message":{"Phrase":"Yo!"}}
        if (token.Type == JTokenType.Object)
        {
            var hello = new Hello1();
            serializer.Populate(token.CreateReader(), hello);
            return hello;
        }
        throw new JsonSerializationException("Message字段格式不合法");
    }

    public override void WriteJson(JsonWriter writer, IHello value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteNull();
            return;
        }
        // 根据配置决定输出格式
        if (_serializeAsString)
        {
            writer.WriteValue(value.Phrase);
        }
        else
        {
            JObject.FromObject(value, serializer).WriteTo(writer);
        }
    }
}

接入方式

原有Greeting类不需要改成泛型实现,保留原有定义即可,两种接入方式可选:

  • 方式1:给属性打特性标记,固定序列化规则
public class Greeting
{
    [JsonConverter(typeof(HelloInterfaceConverter))]
    public IHello Message { get; set; }
}
  • 方式2:全局/单次序列化时传入配置,不需要修改实体类,可动态切换输出格式
// 序列化为简化字符串格式
var stringSettings = new JsonSerializerSettings
{
    Converters = { new HelloInterfaceConverter(serializeAsString: true) }
};
var jsonText = JsonConvert.SerializeObject(greeting, stringSettings);
// 输出:{"Message":"Yo!"}

// 序列化为原有对象格式
var objectSettings = new JsonSerializerSettings
{
    Converters = { new HelloInterfaceConverter(serializeAsString: false) }
};
var jsonText2 = JsonConvert.SerializeObject(greeting, objectSettings);
// 输出:{"Message":{"Phrase":"Yo!"}}

// 反序列化时两种格式都可自动识别,不需要额外配置
var g1 = JsonConvert.DeserializeObject<Greeting>("{\"Message\":\"Yo!\"}", stringSettings);
var g2 = JsonConvert.DeserializeObject<Greeting>("{\"Message\":{\"Phrase\":\"Yo!\"}}", stringSettings);

方案优势

  • 上层使用者完全不需要感知底层处理逻辑,和原来一样实例化Greeting类即可,不需要手动指定泛型参数
  • 同时兼容两种格式的反序列化,不管传入的是字符串还是对象结构都能正常解析
  • 序列化格式可灵活控制,不需要修改业务实体代码
  • 后续如果新增IHello的其他实现类,只需要扩展转换器内的识别逻辑即可,不影响上层调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:33:21