Not sure how to title this question correctly but here is the problem.
public sealed class ObjectPropertySubclassTest
{
private sealed class CleverBaseClassConverter : JsonConverter<BaseClass>
{
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, BaseClass value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override BaseClass ReadJson(JsonReader reader, Type objectType, BaseClass existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var token = JToken.ReadFrom(reader);
if (token["Components"] is JArray)
{
var collection=new CollectionClass();
serializer.Populate(token.CreateReader(), collection);
return collection;
}
else
{
if (token["Value"] is JArray)
{
var obj = new SubClass<IEnumerable<BaseClass>>();
serializer.Populate(token.CreateReader(), obj);
return obj;
}
else
{
var obj = new SubClass<object>();
serializer.Populate(token.CreateReader(), obj);
return obj;
}
}
}
}
[JsonConverter(typeof(CleverBaseClassConverter))]
private abstract class BaseClass
{
public object Value { get; set; }
}
private class SubClass<T>: BaseClass
{
public new T Value
{
get => (T) base.Value;
set => base.Value = value;
}
}
private sealed class CollectionClass : SubClass<IEnumerable<BaseClass>>
{
public IEnumerable<BaseClass> Components { get=>Value; set=>Value=value; }
public bool ShouldSerializeValue() => false;
}
[Test]
public void Test()
{
var item=new CollectionClass
{
Components=new BaseClass[] {new SubClass<string>{Value="hi"},new SubClass<int>{Value=5}, }
};
var json = JsonConvert.SerializeObject(item);
var copy = JsonConvert.DeserializeObject<CollectionClass>(json);
//why does copy.components have 4 items (2 doubling up)?
//why does copy.value have 4 items (2 doubling up) as well?
}
}
Serializaiton works as expected but when i deserialize json into a collection class, it ends up with 4 items instead of 2 (in components). Am i doing something fundamentally wrong here with deserialization? Also why does it still serialize "Value" for collection class
JSON: (I have json converter to deserialize correct subclass)
{"Components":[{"Value":"hi"},{"Value":5}],"Value":[{"Value":"hi"},{"Value":5}]}
I figured out how to make it work and why was it duplicating items
private class SubClass<T>: BaseClass
{
public new T Value
{
get => (T) base.Value;
set => base.Value = value;
}
//Added this here in the generic subclass
public virtual bool ShouldSerializeValue() => true;
}
Then in the collection subsclass
private sealed class CollectionClass : SubClass<IEnumerable<BaseClass>>
{
public IEnumerable<BaseClass> Components { get=>Value; set=>Value=value; }
//this prevents value to be serialized for this type of class
public override bool ShouldSerializeValue() => false;
}
Finally Why it was duplicating it? Because value was serialized and it was aggregating "components" after deserializing value part, after deserializing value it would deserialize coponents which took already deserialized list of values as base and added components to that collection. so stopping value from serializing in case of collection class it would not have underlying json for "values" and hence would not duplicate it.