如何让JsonSerializer.Deserialize<>不将对象反序列化为JsonElement类型?
如何让JsonSerializer.Deserialize<>不将对象反序列化为JsonElement类型?
这个问题我之前也碰到过,System.Text.Json在反序列化为Dictionary<string, object>时,默认会把所有未知类型的JSON值包装成JsonElement,确实挺让人头疼的。不过有几种办法可以解决这个问题:
- 方法一:利用
JsonSerializerOptions.UnknownTypeHandling属性
这是最简便的方案,只需要配置序列化选项,让序列化器自动将JSON基本类型映射为对应的.NET原生类型:
var options = new JsonSerializerOptions { UnknownTypeHandling = JsonUnknownTypeHandling.Object }; var newData = JsonSerializer.Deserialize<Dictionary<string, object>>(json, options); // 现在这个断言会通过,Key2的值是long类型(JSON整数默认转long) Assert.IsType<long>(newData["Key2"]); // Key1会是string类型 Assert.IsType<string>(newData["Key1"]); // Key3会是DateTime类型 Assert.IsType<DateTime>(newData["Key3"]);
需要注意的是,JSON中的整数默认会被转换为long而非int,如果你的业务场景必须用int,可以参考下面的自定义转换器方案。
- 方法二:自定义
JsonConverter实现精确类型控制
如果需要更精细的类型映射(比如把JSON整数强制转成int),可以编写自定义转换器来处理object类型的反序列化:
public class ObjectConverter : JsonConverter<object> { public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.TokenType switch { // 优先尝试转换为int JsonTokenType.Number when reader.TryGetInt32(out int intValue) => intValue, // 再尝试long JsonTokenType.Number when reader.TryGetInt64(out long longValue) => longValue, // 浮点型转double JsonTokenType.Number => reader.GetDouble(), // 尝试转换为DateTime JsonTokenType.String when reader.TryGetDateTime(out DateTime dateTimeValue) => dateTimeValue, // 普通字符串 JsonTokenType.String => reader.GetString(), // 布尔值 JsonTokenType.True => true, JsonTokenType.False => false, // null值 JsonTokenType.Null => null, // 其他类型 fallback 到JsonElement _ => JsonElement.ParseValue(ref reader) }; } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
使用这个转换器时,只需要把它加入序列化选项的转换器集合:
var options = new JsonSerializerOptions { Converters = { new ObjectConverter() } }; var newData = JsonSerializer.Deserialize<Dictionary<string, object>>(json, options); // 现在Key2会是int类型,这个断言可以通过 Assert.IsType<int>(newData["Key2"]);
两种方案各有优势:方法一简单高效,适合大多数通用场景;方法二灵活性强,能满足特殊的类型转换需求,你可以根据自己的业务情况选择。
备注:内容来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

