How to ignore base class JsonConverter when deserializing derived classes?

眉间皱痕 提交于 2019-12-20 04:36:42

问题


I have an abstract base class:

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

And more classes which inherits from it. One of those classes is StringComponent:

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

    public StringComponent(string text)
    {
        Text = text;
    }
}

Converter, which is a JsonConverter applied to TextComponent looks like this:

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);
}

The problem:

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

This goes into an infinite "loop" eventually resulting in a StackOverflow, because when calling DeserializeObject<Stringcomponent> or ToObject<StringComponent>, the JsonConverter of the base class (the Converter) is used which again calls those methods. This is not the desired behavior. When serializing derived classes, they should not be using base class's JsonConverter. If you look at CanConvert method of the Converter, I'm also only allowing it for TextComponent only, not for any of it's derived classes.

So how do I fix this?


回答1:


Did you try to remove the [JsonConvert]-attribute from your base class? In my example I invoke my "custom" converter manually: https://github.com/Code-Inside/Samples/blob/b635580a4966b1b77c93a8b682389c6cf06d2da6/2015/JsonConvertIssuesWithBaseClasses/JsonConvertIssuesWithBaseClasses/Program.cs#L36-L79




回答2:


You can set the converter on the sub class contract to null;

    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();
    }
}


来源:https://stackoverflow.com/questions/46036138/how-to-ignore-base-class-jsonconverter-when-deserializing-derived-classes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!