我正在尝试学习如何使用System.Text.Json将JSON反序列化为一个不可变的POCO对象,该对象除了接受属性的构造函数外还具有复制构造函数。没有默认构造函数。
阅读dotnet运行时github 问题建议为不可变类型使用JsonConverter自定义反序列化过程。
我已尝试并成功反序列化。但是,我想重构反序列化方法,因为它目前是针对3级对象图(请参见下文)反序列化的单体结构。
此时,我正在尝试了解是否可以为对象图中的每个级别都有一个JsonConverter?例如:
JsonSerializerOptions serializeOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
serializeOptions.Converters.Add(new MotionDetectionConverter(logger),
serializeOptions.Converters.Add(new MotionInfoConverter(logger),
serializeOptions.Converters.Add(new MotionMatricesConverter(matrices)
);
是否可能将转换器与正确的JSON片段匹配,还是编写一些小帮助类更容易?
internal sealed class MotionDetectionConverter : JsonConverter<MotionDetection>
{
private HashSet<string> _motionDetectionProps;
private HashSet<string> _motionInfoProps;
private HashSet<string> _motionMatrixProps;
private readonly ILogger _log;
public MotionDetectionConverter(ILogger<MotionDetectionConverter> logger)
{
_log = logger;
_motionMatrixProps = new HashSet<string>(new string[] { "x", "y", "width", "height", "tag", "confidence" });
_motionDetectionProps = new HashSet<string>(new string[] { "group", "time", "monitorId", "plug", "details" });
_motionInfoProps = new HashSet<string>(new string[] { "plug", "name", "reason", "matrices", "img", "imgHeight", "imgWidth", "time" });
}
public override MotionDetection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null) return null;
using (JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader))
{
var jsonObject = jsonDocument.RootElement;
if (!_motionDetectionProps.IsSupersetOf(jsonObject.EnumerateObject().Select(x => x.Name).AsEnumerable()))
{
throw new JsonException();
}
var group = jsonObject.GetProperty("group").ToString();
var time = jsonObject.GetProperty("time").GetDateTimeOffset();
var monitorId = jsonObject.GetProperty("monitorId").ToString();
var plug = jsonObject.GetProperty("plug").ToString();
var details = jsonObject.GetProperty("details");
if (!_motionInfoProps.IsSupersetOf(details.EnumerateObject().Select(x => x.Name).AsEnumerable()))
{
throw new JsonException();
}
var infoPlug = details.GetProperty("plug").ToString();
var infoName = details.GetProperty("name").ToString();
var infoReason = details.GetProperty("reason").ToString();
var infoImg = details.GetProperty("img").ToString();
var infoHeight = details.GetProperty("imgHeight").GetInt32();
var infoWidth = details.GetProperty("imgWidth").GetInt32();
var infoTime = details.GetProperty("time").GetDateTimeOffset();
var infoMatrices = details.GetProperty("matrices").EnumerateArray();
List<MotionLocation> matrices = new List<MotionLocation>();
while (infoMatrices.MoveNext())
{
if (!_motionMatrixProps.IsSupersetOf(infoMatrices.Current.EnumerateObject().Select(prop => prop.Name).AsEnumerable()))
{
throw new JsonException();
}
var x = infoMatrices.Current.GetProperty("x").GetDouble();
var y = infoMatrices.Current.GetProperty("y").GetDouble();
var width = infoMatrices.Current.GetProperty("width").GetDouble();
var height = infoMatrices.Current.GetProperty("height").GetDouble();
var tag = infoMatrices.Current.GetProperty("tag").GetString();
var confidence = infoMatrices.Current.GetProperty("confidence").GetDouble();
matrices.Add(new MotionLocation(x, y, width, height, tag, confidence));
}
MotionInfo info = new MotionInfo(infoPlug, infoName, infoReason, matrices, infoImg, infoHeight, infoWidth, infoTime);
return new MotionDetection(group, time, monitorId, plug, info);
}
}
public override void Write(Utf8JsonWriter writer, MotionDetection motionDetection, JsonSerializerOptions options) =>
writer.WriteStringValue(@"motionDetection");
// to complete....
}