如何在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
相关产品推荐
相关产品推荐

