System.Text.Json动态类型处理:自定义object属性反序列化优化
解决System.Text.Json反序列化Dictionary<string, object>时转为JsonElement的问题
针对你在Blazor动态数据绑定中遇到的问题,这里提供两种简洁的解决方案:
方案一:自定义JsonConverter,反序列化时直接转为真实.NET类型
创建一个专门处理Dictionary<string, object>的Json转换器,在反序列化阶段自动将JsonElement转换为对应的.NET原生类型,无需后续手动处理:
public class ObjectDictionaryConverter : JsonConverter<Dictionary<string, object>> { public override Dictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException("Expected start of object"); } var dictionary = new Dictionary<string, object>(); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) { return dictionary; } if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException("Expected property name"); } string propertyName = reader.GetString(); reader.Read(); dictionary[propertyName] = ReadValue(ref reader, options); } throw new JsonException("Unexpected end of JSON"); } private object ReadValue(ref Utf8JsonReader reader, JsonSerializerOptions options) { return reader.TokenType switch { JsonTokenType.String => reader.GetString(), JsonTokenType.Number when reader.TryGetInt64(out long l) => l, JsonTokenType.Number when reader.TryGetDouble(out double d) => d, JsonTokenType.True => true, JsonTokenType.False => false, JsonTokenType.Null => null, JsonTokenType.StartArray => JsonSerializer.Deserialize<List<object>>(ref reader, options), JsonTokenType.StartObject => JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options), _ => throw new JsonException($"Unsupported token type: {reader.TokenType}") }; } public override void Write(Utf8JsonWriter writer, Dictionary<string, object> value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, options); } }
使用方式
在反序列化时,将转换器添加到JsonSerializerOptions中:
var options = new JsonSerializerOptions(); options.Converters.Add(new ObjectDictionaryConverter()); var result = await httpClient.GetFromJsonAsync<DynamicDataGridResult>("your-api-url", options);
这样反序列化后的Data属性里的对象就直接是对应类型(string、int、bool等),无需再做后处理。
方案二:封装后处理逻辑,用扩展方法简化类型转换
如果不想自定义转换器,可以写一个通用的扩展方法来处理JsonElement到.NET类型的转换,避免重复的类型判断:
public static class JsonElementExtensions { public static object ConvertToObject(this JsonElement element) { return element.ValueKind switch { JsonValueKind.String => element.GetString(), JsonValueKind.Number when element.TryGetInt64(out long l) => l, JsonValueKind.Number when element.TryGetDouble(out double d) => d, JsonValueKind.True => true, JsonValueKind.False => false, JsonValueKind.Null => null, JsonValueKind.Array => element.EnumerateArray().Select(e => e.ConvertToObject()).ToList(), JsonValueKind.Object => element.EnumerateObject() .ToDictionary(p => p.Name, p => p.Value.ConvertToObject()), _ => throw new NotSupportedException($"Unsupported JsonValueKind: {element.ValueKind}") }; } }
使用方式
遍历Data中的字典,批量转换值:
foreach (var dict in result.Data) { foreach (var key in dict.Keys.ToList()) { if (dict[key] is JsonElement element) { dict[key] = element.ConvertToObject(); } } }
这样只需要维护这一个扩展方法,后续新增类型支持也只需要在switch里添加即可,大幅降低重复代码。
内容的提问来源于stack exchange,提问作者AFract
相关产品推荐
相关产品推荐

