如何通过System.Text.Json反序列化泛型类型?
泛型类JSON反序列化保留类型信息的优化方案
针对你遇到的泛型类TestModel<T>反序列化时需保留并识别泛型参数类型的问题,以下是几种更合理的实现方案:
方案1:利用Newtonsoft.Json内置类型信息支持
Newtonsoft.Json可通过TypeNameHandling配置自动在JSON中嵌入泛型类型信息,反序列化时直接识别,无需手动拼接类型标识。
序列化配置与示例
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, // 自动为泛型/多态类型添加类型标记 DateFormatString = "yyyy-MM-dd HH:mm:ss" }; // 序列化TestModel<string>实例 var model = new TestModel<string> { Name = "123", Parameter = "456", Time = DateTime.Parse("2023-12-4 06:46:01") }; string json = JsonConvert.SerializeObject(model, settings);
生成的JSON会包含$type字段,示例:
{ "$type": "你的命名空间.TestModel`1[System.String], 你的程序集名称", "Name": "123", "Parameter": "456", "Time": "2023-12-4 06:46:01" }
反序列化与类型处理
var deserializedModel = JsonConvert.DeserializeObject(json, settings); // 根据泛型类型执行对应逻辑 if (deserializedModel is TestModel<string> stringModel) { // 处理string类型参数的逻辑 } else if (deserializedModel is TestModel<List<int>> intListModel) { // 处理列表类型参数的逻辑 }
注意:使用TypeNameHandling需注意安全风险,建议配合SerializationBinder限制允许反序列化的类型,避免注入攻击。
方案2:使用System.Text.Json原生类型支持(.NET Core 3.0+)
如果项目基于.NET Core/.NET 5+,可使用System.Text.Json的特性或自定义解析器实现类型识别。
方式A:特性标记已知泛型类型
提前标记TestModel<T>的所有可能泛型实例类型:
[JsonDerivedType(typeof(TestModel<string>), typeDiscriminator: "StringModel")] [JsonDerivedType(typeof(TestModel<List<int>>), typeDiscriminator: "IntListModel")] public class TestModel<T> { public string Name { get; set; } public T Parameter { get; set; } public DateTime Time { get; set; } }
序列化与反序列化:
var options = new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver(), WriteIndented = true }; // 序列化 var model = new TestModel<string> { Name = "123", Parameter = "456", Time = DateTime.Parse("2023-12-4 06:46:01") }; string json = JsonSerializer.Serialize(model, options); // 反序列化并识别类型 var deserialized = JsonSerializer.Deserialize<TestModel<object>>(json, options); Type paramType = deserialized.GetType().GetGenericArguments()[0]; if (paramType == typeof(string)) { var stringModel = (TestModel<string>)deserialized; // 处理逻辑 }
方式B:动态添加类型解析器
若泛型参数类型不确定,可自定义解析器动态添加类型标识:
var resolver = new DefaultJsonTypeInfoResolver(); resolver.Modifiers.Add(typeInfo => { if (typeInfo.Type.IsGenericType && typeInfo.Type.GetGenericTypeDefinition() == typeof(TestModel<>)) { typeInfo.TypeInfoResolverOptions.TypeDiscriminatorPropertyName = "$type"; // 添加所有需要支持的泛型实例类型 var knownTypes = new[] { typeof(TestModel<string>), typeof(TestModel<List<int>>), typeof(TestModel<CustomClass>) }; foreach (var type in knownTypes) { typeInfo.PolymorphicTypeDiscriminators.Add(type, type.FullName); } } }); var options = new JsonSerializerOptions { TypeInfoResolver = resolver }; // 序列化与反序列化流程同上
方案3:自定义类型字段嵌入JSON
如果不想依赖序列化库的内置功能,可手动在TestModel<T>中添加类型标识字段,序列化时写入泛型参数类型信息。
修改模型类
public class TestModel<T> { public string Name { get; set; } public T Parameter { get; set; } public DateTime Time { get; set; } // 自动返回泛型参数T的类型全名 public string ParameterType => typeof(T).FullName; }
分两步反序列化
- 先读取类型标识,再创建对应泛型类型反序列化:
// 第一步:读取类型信息 dynamic temp = JsonConvert.DeserializeObject(json); string typeName = temp.ParameterType; Type paramType = Type.GetType(typeName); // 第二步:创建泛型类型并反序列化 Type genericModelType = typeof(TestModel<>).MakeGenericType(paramType); object model = JsonConvert.DeserializeObject(json, genericModelType); // 根据类型处理逻辑 if (paramType == typeof(string)) { var stringModel = (TestModel<string>)model; // 处理逻辑 }
方案对比
- 方案1:配置简单,适合已使用Newtonsoft.Json的项目,需注意安全风险。
- 方案2:原生支持.NET Core/.NET 5+,配置稍复杂但可控性强。
- 方案3:不依赖库特性,兼容性高,适合需完全自定义类型标识逻辑的场景。
内容的提问来源于stack exchange,提问作者Melon NG
相关产品推荐
相关产品推荐

