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

如何通过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;
}

分两步反序列化

  1. 先读取类型标识,再创建对应泛型类型反序列化:
// 第一步:读取类型信息
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:27:41