反序列化派生类时如何忽略基类 JsonConverter?

Win*_*don 3 c# json.net

我有一个抽象基类:

[JsonConverter(typeof(Converter))]
public abstract class TextComponent {
    ...
    public bool Bold { get; set; }
    public TextComponent[] Extra { get; set; }
    ...
}
Run Code Online (Sandbox Code Playgroud)

以及更多继承自它的类。其中一类是StringComponent

public sealed class StringComponent : TextComponent
{
    public string Text { get; set; }

    public StringComponent(string text)
    {
        Text = text;
    }
}
Run Code Online (Sandbox Code Playgroud)

Converter,这是一个JsonConverter应用于TextComponent看起来像这样:

private sealed class Converter : JsonConverter
{
    ....

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        var tok = JToken.Load(reader);
        switch (tok)
        {
            ...
            case JObject x:
                var dic = (IDictionary<string, JToken>) x;
                if (dic.ContainsKey("text")) return x.ToObject<StringComponent>();
                ...
            ...
        }
    }
    ...
    public override bool CanConvert(Type objectType) => objectType == typeof(TextComponent);
}
Run Code Online (Sandbox Code Playgroud)

问题

var str = "{\"text\":\"hello world\"}";
var obj = JsonConvert.DeserializeObject<TextComponent>(str);
// this doesn't work either:
var obj = JsonConvert.DeserializeObject<StringComponent>(str);
Run Code Online (Sandbox Code Playgroud)

这进入无限“循环”,最终导致 a StackOverflow,因为在调用DeserializeObject<Stringcomponent>or 时ToObject<StringComponent>JsonConverter使用基类 (the Converter) 的 再次调用这些方法。这不是理想的行为。序列化派生类时,它们不应使用基类的JsonConverter. 如果你看看 的CanConvert方法Converter,我也只允许它TextComponent,而不是它的任何派生类。

那么我该如何解决这个问题?

小智 5

您可以将子类合约上的转换器设置为空;

    public override bool CanWrite => false;
    public override bool CanRead => true;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (objectType == typeof(BaseClass))
        {
            JObject item = JObject.Load(reader);
            if (item["isClass2"].Value<bool>())
            {
                return item.ToObject<ChildClass2>(serializer);
            }
            else
            {
                return item.ToObject<ChildClass1>(serializer);
            }
        }
        else
        {
            serializer.ContractResolver.ResolveContract(objectType).Converter = null;
            return serializer.Deserialize(reader, objectType);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)