C# Web API中泛型EntryDto的JSON序列化/反序列化方案
一、开箱即用的反序列化方案 C#主流的JSON序列化库都支持直接泛型反序列化,完全满足你的需求:
1. System.Text.Json(.NET Core 3.0+内置) Web API默认使用的官方库,直接指定泛型类型即可完成反序列化:
// 示例:反序列化为string类型的EntryDto
var json = "{\"Value\": \"hello world\"}";
var stringEntry = JsonSerializer.Deserialize<EntryDto<string>>(json);
// 示例:反序列化为int类型的EntryDto
var intJson = "{\"Value\": 123}";
var intEntry = JsonSerializer.Deserialize<EntryDto<int>>(intJson);
2. Newtonsoft.Json(Json.NET) 如果项目依赖老牌的Json.NET,写法类似:
var boolJson = "{\"Value\": true}";
var boolEntry = JsonConvert.DeserializeObject<EntryDto<bool>>(boolJson);
二、包含EntryDto列表的请求/响应类 完全可以创建这类泛型请求/响应类,分两种场景处理:
1. 单一类型的列表 如果列表中所有EntryDto的泛型类型T一致,直接定义泛型容器类即可:
// 泛型请求类
public class EntryListRequest<T>
{
public List<EntryDto<T>> Entries { get; set; } = new List<EntryDto<T>>();
}
// 泛型响应类
public class EntryListResponse<T>
{
public List<EntryDto<T>> Entries { get; set; } = new List<EntryDto<T>>();
public bool IsSuccess { get; set; }
public string? Message { get; set; }
}
使用时明确指定T的类型:
// 反序列化int类型的请求
var requestJson = "{\"Entries\": [{\"Value\": 1}, {\"Value\": 2}, {\"Value\": 3}]}";
var intRequest = JsonSerializer.Deserialize<EntryListRequest<int>>(requestJson);
// 序列化string类型的响应
var stringResponse = new EntryListResponse<string>
{
Entries = new List<EntryDto<string>>
{
new() { Value = "first" },
new() { Value = "second" }
},
IsSuccess = true
};
var responseJson = JsonSerializer.Serialize(stringResponse);
2. 混合类型的列表(T为不同类型) 如果需要在同一个列表中存放不同T类型的EntryDto(同时包含string、int、bool等),静态泛型无法直接支持,可通过两种方案解决:
方案一:使用EntryDto兼容多类型
反序列化后通过类型判断处理不同值:
var mixedJson = "{\"Entries\": [{\"Value\": \"test\"}, {\"Value\": 456}, {\"Value\": false}]}";
var mixedEntries = JsonSerializer.Deserialize<List<EntryDto<object>>>(mixedJson);
foreach (var entry in mixedEntries)
{
switch (entry.Value)
{
case string s:
Console.WriteLine($"字符串值:{s}");
break;
case int i:
Console.WriteLine($"整数值:{i}");
break;
case bool b:
Console.WriteLine($"布尔值:{b}");
break;
}
}
注意:System.Text.Json默认会将JSON数字反序列化为long,若要精准识别int,需配置序列化选项:
var options = new JsonSerializerOptions
{
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
方案二:通过多态序列化实现类型识别 创建非泛型基类,让EntryDto继承并配置类型鉴别:
public abstract class EntryDtoBase
{
public abstract object GetValue();
}
public class EntryDto<T> : EntryDtoBase
{
public T Value { get; set; } = default!;
public override object GetValue() => Value;
}
配置System.Text.Json的多态序列化规则:
var options = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers = { typeInfo =>
{
if (typeInfo.Type == typeof(EntryDtoBase))
{
typeInfo.PolymorphismOptions = new JsonPolymorphismOptions
{
DerivedTypes =
{
new JsonDerivedType(typeof(EntryDto<string>), "string"),
new JsonDerivedType(typeof(EntryDto<int>), "int"),
new JsonDerivedType(typeof(EntryDto<bool>), "bool"),
new JsonDerivedType(typeof(EntryDto<double>), "double")
}
};
}
}
}
}
};
// 序列化混合类型列表
var mixedList = new List<EntryDtoBase>
{
new EntryDto<string> { Value = "demo" },
new EntryDto<int> { Value = 789 },
new EntryDto<bool> { Value = true }
};
var serializedJson = JsonSerializer.Serialize(mixedList, options);
// 反序列化
var deserializedList = JsonSerializer.Deserialize<List<EntryDtoBase>>(serializedJson, options);
此方案需要前端在JSON中携带类型标识(如"$type": "string"),确保后端能正确识别类型。
注意事项 前端传递JSON时,需保证Value的类型与后端预期的T类型匹配,否则会抛出反序列化异常。 对于可空类型(如int?),需确保JSON中的值为null或对应类型的有效值。 混合类型场景建议优先使用EntryDto<object>方案,业务逻辑更简洁;多态方案适合强类型要求高的场景。 内容的提问来源于stack exchange,提问作者kristofdc