内容纲要
当一个字段为 object 类型时,System.Text.Json 自动设置 JsonElement 类型,而不是对应的类型,因此在很多情况下会出现奇怪的问题。
因此这里只要有两个地方加上代码,缓解这一情况。
第一步,实现转换器,当一个类型是 object 时,如果 json 是简单类型,则直接使用实际类型,而不是 JsonElement。
但是当字段是字典、数组,如 object[]
,T[]
但是 T 中有 object 字段 等情况时,这里是无效的。
public class ObjectJsonSerializer : IJsonSerializer
{
private readonly JsonSerializerOptions _options;
public ObjectJsonSerializer()
{
_options = new JsonSerializerOptions();
_options.Converters.Add(new ObjectToInferredTypesConverter());
}
/// <inheritdoc />
public TObject? Deserialize<TObject>(ReadOnlySpan<byte> bytes)
where TObject : class
{
return System.Text.Json.JsonSerializer.Deserialize<TObject>(bytes, _options);
}
/// <inheritdoc />
public byte[] Serializer<TObject>(TObject obj)
where TObject : class
{
return System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(obj, _options);
}
}
public class ObjectToInferredTypesConverter : JsonConverter<object>
{
public override object Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) => reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number when reader.TryGetInt64(out long l) => l,
JsonTokenType.Number => reader.GetDouble(),
JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime,
JsonTokenType.String => reader.GetString()!,
_ => JsonDocument.ParseValue(ref reader).RootElement.Clone()
};
public override void Write(
Utf8JsonWriter writer,
object objectToWrite,
JsonSerializerOptions options) =>
System.Text.Json.JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
}
然后为了适配更多情况,只能手动转换,下面是扩展方法:
/// <summary>
/// 扩展.
/// </summary>
public static class JsonConvertExtensions
{
/// <summary>
/// 转换为对应类型.
/// </summary>
/// <param name="json"></param>
/// <returns>object.</returns>
public static object? ToObject(this JsonElement json)
{
switch (json.ValueKind)
{
case JsonValueKind.True:
return json.GetBoolean();
case JsonValueKind.False:
return json.GetBoolean();
case JsonValueKind.String:
return json.GetString();
case JsonValueKind.Null:
return null;
case JsonValueKind.Object:
return json;
case JsonValueKind.Number:
return json.GetInt32();
}
return json;
}
/// <summary>
/// 转换为对应类型.
/// </summary>
/// <param name="obj"></param>
/// <returns>object.</returns>
public static object? ToObject(this object? obj)
{
if (obj == null)
{
return obj;
}
if (obj is JsonElement json)
{
switch (json.ValueKind)
{
case JsonValueKind.True:
return json.GetBoolean();
case JsonValueKind.False:
return json.GetBoolean();
case JsonValueKind.String:
return json.GetString();
case JsonValueKind.Null:
return null;
case JsonValueKind.Object:
return json;
case JsonValueKind.Number:
return json.GetInt32();
}
return json;
}
return obj;
}
}
对于数组等类型,只能手动使用扩展方法:
for (int i = 0; i < message.Body.Data.Length; i++)
{
message.Body.Data[i].Value = message.Body.Data[i].Value.ToObject();
}
文章评论