使用泛型时 System.Text.Json 的自定义转换器

Custom converter for System.Text.Json when working with generics

我有一个包含通用 (object) 的 class,可以用 stringintbool 或相同 class 的另一个实例。以前,在使用 Newtonsoft.Json 时,我有一个自定义转换器,它会根据 JToken.Type 是否为 JTokenType.Object 来确定如何反序列化(检测该值可能是相同 [= 的另一个实例) 56=]).

使用 System.Text.JsonJsonConverter,我看不出有什么办法可以做到这一点。看来我必须执行 .Read() 来给出下一个标记(StartObjectEndObjectStartArray、... String 等)。

我看到 reader.GetString() 的设施可以提取值,(与 .GetInt32() 和其他人相同),但无法 读取下一个对象 。也就是说,如果我确定 属性 的值是同一 class 的另一个实例,我想完整地读取该对象并将其分配给 属性.

我的 Newtonsoft.Json 转换器如下(请注意,当它在 Left 或 [=31= 中遇到相同 class 的实例时,它会递归调用反序列化方法] 属性):

public class ExpressionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Expression));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Expression ret = new Expression();
        JObject jo = JObject.Load(reader);
        if (jo["Left"] != null)
        {
            JToken leftToken = jo["Left"];
            if (leftToken.Type == JTokenType.Object)
            {
                ret.Left = SerializationHelper.DeserializeJson<Expression>(leftToken.ToString());
            }
            else if (leftToken.Type == JTokenType.Array)
            {
                ret.Left = leftToken.ToObject<List<object>>();
            }
            else
            {
                ret.Left = leftToken.ToObject<string>();
            }
        }

        ret.Operator = (OperatorEnum)(Enum.Parse(typeof(OperatorEnum), jo["Operator"].ToString()));

        if (jo["Right"] != null)
        {
            JToken rightToken = jo["Right"];
            if (rightToken.Type == JTokenType.Object)
            {
                ret.Right = SerializationHelper.DeserializeJson<Expression>(rightToken.ToString());
            }
            else if (rightToken.Type == JTokenType.Array)
            {
                ret.Right = rightToken.ToObject<List<object>>();
            }
            else
            {
                ret.Right = rightToken.ToObject<string>();
            }
        }

        return ret;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

我的问题是:我可以读出整个对象(一些标记系列)以分配给 LeftRight 属性 吗?

编辑:更多上下文。 Expression class 是:

public class Expression
{
  public object Left { get; set; } = null;
  public OperatorEnum Operator { get; set; } = OperatorEnum.Equals;
  public object Right { get; set; } = null;
}

并且输入 JSON 看起来像这样简单:

{
  "Left": "Amount",
  "Operator": "GreaterThan",
  "Right": 100.00
}

或complex/nested喜欢:

{
  "Left": {
    "Left": {
      "Left": "Amount",
      "Operator": "GreaterThan",
      "Right": 100.00
    },
    "Operator": "And",
    "Right": {
      "Left": "NameOnCard",
      "Operator": "Contains",
      "Right": "Smith"
    }
  },
  "Operator": "And",
  "Right": {
    "Left": {
      "Left": "Brand",
      "Operator": "Equals",
      "Right": "Visa"
    },
    "Operator": "Or",
    "Right": {
      "Left": "Brand",
      "Operator": "Equals",
      "Right": "Mastercard"
    }
  }
}

与 Newtonsoft.Json 一样,您似乎可以递归调用 JsonSerializer.Deserialize 并将 ref Utf8JsonReader 与自定义序列化程序一起作为参数传递。

这是自定义序列化程序中的代码:

if (reader.TokenType == JsonTokenType.StartObject)
{
    ret.Right = JsonSerializer.Deserialize<Expression>(ref reader, new JsonSerializerOptions
    {
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        Converters = { new JsonStringEnumConverter(), new ExpressionConverter() },
    });
}

反序列化器将在递归停止的地方继续。工作得很好。