问题
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