using System.Collections.Generic;
using System.Text.Json.Serialization;
static void Main(string[] args)
var models = new IBase[] { new Foo { name = "john" }, new Bar { age = 10 } };
var options = new JsonSerializerOptions {
Converters = { new BaseConverter() }
var json = JsonSerializer.Serialize(models, options);
Console.WriteLine($"Output: {json}");
var result = JsonSerializer.Deserialize<IBase[]>(json, options);
foreach (var i in result!) Console.WriteLine(i);
public class BaseConverter : JsonConverter<IBase> {
public static Dictionary<string, Type> mapping = new() {
public override bool CanConvert(Type type) => type.IsAssignableFrom(typeof(IBase));
public override IBase? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
return ReadBase(ref reader, typeToConvert, options);
public IBase? ReadFoo(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
return (IBase?) JsonSerializer.Deserialize(ref reader, typeof(Foo), options);
public IBase? ReadBase(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
if (reader.TokenType != JsonTokenType.StartObject) throw new JsonException();
if (reader.TokenType != JsonTokenType.PropertyName) throw new JsonException();
if (reader.GetString() != "type") throw new JsonException();
if (reader.TokenType != JsonTokenType.String) throw new JsonException();
var t = reader.GetString();
mapping.TryGetValue(t ?? "", out Type? type);
if (type == null) throw new JsonException($"{t} is not a recognized type");
Console.WriteLine($"Saw {type}");
Console.WriteLine($"{reader.TokenStartIndex} {reader.TokenType}");
Console.WriteLine($"{current.TokenStartIndex} {current.TokenType}");
var result = (IBase?) JsonSerializer.Deserialize(ref current, type, options);
public override void Write(Utf8JsonWriter writer, IBase value, JsonSerializerOptions options)
var type = value.GetType();
JsonSerializer.Serialize(writer, value, type, options);
public string type { get; }
public class Foo : IBase {
public string type => "Foo";
public string name { get; set; } = "";
public override string ToString() => $"Foo(name = {name})";
public class Bar : IBase {
public string type => "Bar";
public int age { get; set; } = 0;
public override string ToString() => $"Bar(name = {age})";