So you’ve decided you needed to use inheritance within your object model but are struggling to serialize all the data present on the instances of the types. In a previous post, I wrote about serializing an interface instances using a TypeConverter and you should definitely read that, as this post takes a part from that post. I’ve decided to pull the solution into its own post to make it easier to find for folks.

In this short and simple blog post, you’ll see how to take an array of varying types and serialize all the data, not just the common base class.

The Problem

Say you have a Vehicle base class and want to derive several different vehicles like Car and Bicycle.

public abstract class Vehicle
{
    public int NumberOfWheels { get; protected set; }
}

public class Car: Vehicle
{
    public Car()
    {
        NumberOfWheels = 4;
    }

    public string Make { get; set; }
    public string Model { get; set; }
}

public class Bicycle: Vehicle
{
    public Bicycle()
    {
        NumberOfWheels = 2;
    }

    public string Manufacturer { get; set; }
}

And let us say you have these elements declared in a single variable of Vehicle[].

var vehicles = new Vehicle[]
{
    new Car {Make = "Audi", Model = "A4"},
    new Bicycle {Manufacturer = "Schwinn"}
};
var types = JsonSerializer.Serialize(vehicles);

When you go to use System.Text.Json and the JsonSerializer class, you’ll receive the following string JSON output.

 [{"NumberOfWheels":4},{"NumberOfWheels":2}]

As you may have noticed, the serialization process treated each entry in our array as a Vehicle and not the derived type. The result is because the JsonSerializer class looks at the declared type of our parameter to determine the type when we explicitly stated the variable in our code.

The Polymorphic Serialization Solution

To get JsonSerializer to determine the type of each instance correctly, we need to cast our Vehicle[] to an object[]. When the JsonSerializer sees that a parameter type is object, the serializer will call the GetType method on our instances. Here’s the implementation inside of JsonSerializer that performs the type-determination logic.

private static Type GetRuntimeType<TValue>(in TValue value)
{
    if (typeof(TValue) == typeof(object) && value != null)
    {
        return value.GetType();
    }

    return typeof(TValue);
}

So, it’s surprisingly easy to get the behavior you want. Cast a collection or type to the object type before calling JsonSerializer.Serialize to get polymorphic serialization.

static void Main(string[] args)
{
    var vehicles = new Vehicle[]
    {
        new Car {Make = "Audi", Model = "A4"},
        new Bicycle {Manufacturer = "Schwinn"}
    };

    // All types will be serialized a the base class 
    // of Vehicle, likely not what you want to happen
    var types = JsonSerializer.Serialize(vehicles);
    Console.WriteLine($"As Vehicle[]: {types}");
    
    // ** The Solution **
    // cast your collection to object[]
    // or cast a single instance to an object
    var objects = JsonSerializer.Serialize((object[]) vehicles);
    Console.WriteLine($"As Object[]: {objects}");
}

Running the code above, you’ll see the following results in your console output.

As Vehicle[]: [{"NumberOfWheels":4},{"NumberOfWheels":2}]
As Object[]: [{"Make":"Audi","Model":"A4","NumberOfWheels":4},{"Manufacturer":"Schwinn","NumberOfWheels":2}]

Great! I hope you found this post helpful, and as always, thanks for reading.