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

如何反序列化时而为字典时而为空数组的JSON?

解决Newtonsoft.Json中字典/空数组混合结构的反序列化问题

问题场景

需要反序列化的JSON中,details字段存在两种结构:

  • 正常数据时为字典结构(如示例中的goodJson)
  • 无数据时为空数组(如示例中的badJson)
    直接反序列化会抛出JsonSerializationException,自定义转换器后虽不再报错,但正常结构的Details属性反序列化后为空字典——转换器内部能读取到数据,最终对象里却计数为0。

问题原因分析

之前的转换器大概率存在以下问题:

  • 处理字典结构时,没有正确将JSON对象的键值对映射到Dictionary<TKey, TValue>实例中
  • 可能误将字典结构当成数组处理,或是创建字典实例后未正确填充数据

正确的自定义转换器实现

以下是兼容空数组和字典结构的转换器(以Dictionary<string, object>为例,可根据实际需求修改泛型参数):

public class DictionaryOrEmptyArrayConverter : JsonConverter<Dictionary<string, object>>
{
    public override Dictionary<string, object> ReadJson(JsonReader reader, Type objectType, Dictionary<string, object> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 处理空数组场景
        if (reader.TokenType == JsonToken.StartArray)
        {
            serializer.Deserialize(reader, typeof(List<object>));
            return new Dictionary<string, object>();
        }

        // 处理字典/对象场景
        if (reader.TokenType == JsonToken.StartObject)
        {
            var dict = existingValue ?? new Dictionary<string, object>();
            var jObject = JObject.Load(reader);
            foreach (var property in jObject.Properties())
            {
                dict[property.Name] = property.Value.ToObject<object>(serializer);
            }
            return dict;
        }

        // 其他异常场景返回空字典
        return new Dictionary<string, object>();
    }

    public override void WriteJson(JsonWriter writer, Dictionary<string, object> value, JsonSerializer serializer)
    {
        // 序列化时:字典为空则输出空数组,否则输出对象
        if (value == null || value.Count == 0)
        {
            writer.WriteStartArray();
            writer.WriteEndArray();
        }
        else
        {
            serializer.Serialize(writer, value);
        }
    }
}

使用方式

在目标类的Details属性上标记转换器:

public class MyModel
{
    [JsonConverter(typeof(DictionaryOrEmptyArrayConverter))]
    public Dictionary<string, object> Details { get; set; }
}

测试验证

针对两种JSON结构测试:

// 正常字典结构JSON
var goodJson = @"{""Details"": {""key1"": ""value1"", ""key2"": ""value2"", ""key3"": ""value3"", ""key4"": ""value4""}}";
var goodModel = JsonConvert.DeserializeObject<MyModel>(goodJson);
Console.WriteLine(goodModel.Details.Count); // 输出4

// 空数组结构JSON
var badJson = @"{""Details"": []}";
var badModel = JsonConvert.DeserializeObject<MyModel>(badJson);
Console.WriteLine(badModel.Details.Count); // 输出0,无报错

关键修复点

  1. 明确区分JsonToken.StartArray和JsonToken.StartObject两种类型,避免逻辑混淆
  2. 处理字典时,通过JObject.Load(reader)加载完整对象数据,遍历属性填充字典,确保所有键值对被正确添加
  3. 复用已有字典实例(existingValue),避免因创建新实例导致数据丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 15:40:28