Description
openedon Apr 22, 2021
I need to add $type property for an array that will contain objects of different types ex : ( [A,B,C] of IEnumerable< A> => [A,{$type:"B",$value:B},{$type:"C",$value:C}] )
My custom JsonConverter will have a JsonSerializer.Serialize in the Write method but that resets the state of the serialization so It can no more check the cycles :
private abstract class AbstractEnumerableJsonConverter<TObj, TCollection> :
JsonConverter<TCollection> where TCollection: IEnumerable<TObj>
{
public override TCollection? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var list = new List<TObj>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndArray)
{
break;
}
if (reader.TokenType == JsonTokenType.StartObject)
{
var deserializedObj = default(TObj);
var document = JsonDocument.ParseValue(ref reader);
if (document.RootElement.TryGetProperty("$type", out var typeName))
{
var type = Type.GetType(typeName.GetString());
if (type.IsAssignableTo(typeof(IDbo)))
deserializedObj = (TObj)JsonSerializer.Deserialize(document.RootElement.GetProperty("$value").GetRawText(), type, options);
}
deserializedObj ??= (TObj)JsonSerializer.Deserialize(document.RootElement.ToString(), typeof(TObj), options);
list.Add(deserializedObj);
}
}
var ret = (IList)Activator.CreateInstance(typeToConvert, list.Count);
if (ret.Count == 0)
for (var i = 0; i < list.Count; ++i)
ret.Add(list[i]);
else
for (var i = 0; i < ret.Count; ++i)
ret[i] = list[i];
return (TCollection)ret;
}
public override void Write(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options)
{
writer.WriteStartArray();
foreach (var obj in value)
{
if( obj.GetType() != typeof(TObj))
{
writer.WriteStartObject();
writer.WriteString("$type", obj.GetType().FullName);
writer.WritePropertyName("$value");
JsonSerializer.Serialize(writer, obj, options); //<---- The state is lost so we can no more check cycles**
writer.WriteEndObject();
}
else
JsonSerializer.Serialize(writer, obj, options); //<---- The state is lost so we can no more check cycles**
}
writer.WriteEndArray();
}
}
I have tried to do something like dotnet/docs#21777 (comment) , but it seems that IgnoreCycles relies on a lot of things that are internal and resides in the Core code ( like PushReferenceForCycleDetection that maybe would help if it's protected and not internal
Is there any way I can get around these cycles?
(I have also tried to serialize the properties of the object one by one to avoid calling JsonSerializer.Serialize, but the code to enumerate one object's properties is also internal )
Originally posted by @YeskaNova in dotnet/docs#21777 (comment)