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

如何在JSON.net中设置默认List<T>转换器(无需特性)

解决JSON.net泛型转换器全局注册及特殊集合序列化规则问题

核心思路

因为泛型ArrayObjectConverter<T>无法直接添加到JsonSerializerSettings的转换器列表,我们可以通过自定义契约解析器(ContractResolver) 动态为所有集合类型绑定对应的泛型转换器实例,既不用给每个属性加特性,又能保证反序列化性能——契约解析器只会在首次处理类型时生成并缓存契约,后续复用缓存结果,性能损耗极低。

具体实现

1. 自定义契约解析器

这个解析器会自动识别集合类型(排除字符串),并为其绑定对应的ArrayObjectConverter<T>实例:

public class ArrayObjectContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        Type propertyType = property.PropertyType;

        // 筛选出集合类型(排除string,因为string也实现了IEnumerable)
        if (typeof(IEnumerable).IsAssignableFrom(propertyType) && propertyType != typeof(string))
        {
            Type elementType = GetElementType(propertyType);
            if (elementType != null)
            {
                // 动态创建对应泛型转换器实例
                Type converterType = typeof(ArrayObjectConverter<>).MakeGenericType(elementType);
                property.Converter = (JsonConverter)Activator.CreateInstance(converterType);
            }
        }

        return property;
    }

    // 获取集合的元素类型
    private Type GetElementType(Type collectionType)
    {
        // 优先处理泛型集合(如List<T>、T[])
        if (collectionType.IsGenericType && collectionType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            return collectionType.GetGenericArguments()[0];
        }

        // 处理非泛型集合(如ArrayList,不需要可删除此段)
        foreach (Type interfaceType in collectionType.GetInterfaces())
        {
            if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            {
                return interfaceType.GetGenericArguments()[0];
            }
        }

        return null;
    }
}

2. 全局注册配置

将契约解析器加入JsonSerializerSettings,作为全局默认配置:

// 可封装为单例避免重复创建,提升性能
public static class JsonGlobalSettings
{
    public static readonly JsonSerializerSettings Default = new JsonSerializerSettings
    {
        ContractResolver = new ArrayObjectContractResolver(),
        // 按需添加其他配置,如NullValueHandling、Formatting等
    };
}

// 序列化示例
var data = new { SomeArr = new[] { new { prop1 = "value1" }, new { prop1 = "value2" } } };
string serializedJson = JsonConvert.SerializeObject(data, JsonGlobalSettings.Default);
// 输出:{"SomeArr":{"item1":{"prop1":"value1"},"item2":{"prop1":"value2"}}}

// 反序列化示例
string emptyArrJson = "{\"SomeArr\":[]}";
var result = JsonConvert.DeserializeObject<YourTargetClass>(emptyArrJson, JsonGlobalSettings.Default);
// 正确反序列化为空集合

性能优化说明

  • 契约缓存:DefaultContractResolver会自动缓存生成的类型契约,首次处理后无需重复反射创建转换器,对反序列化速度影响极小。
  • 精准匹配:仅针对集合类型绑定转换器,不会干扰其他类型的序列化逻辑。
  • 单例复用:将JsonSerializerSettings设为单例,避免重复创建解析器和配置对象,进一步降低性能损耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 11:39:18