7

JSON.NET (by Newtonsoft) has great support for serializing and deserializing complex objects.

I am curious about using System.Text.Json instead of JSON.NET and I am not able to find a good tutorial on the internet.

The .NET 7 preview has support for deserializing polymorphic objects. Here is an example using .NET 7 preview and C# 11:

// _To run it you will need net7 preview and c# 11_

using System.Text.Json.Serialization;

var testPolymorphism = new TestPolymorphysm()
{
    Animals = new List<Animal>()
    {
        new Fish() {
             Id = "fish1",
             Name = "GoldFish",
             Action = new ActionSwim() { DistanceSwam = 10 }
        },
        new Dog() {
             Id = "dog1",
             Name = "Tom",
             Action = new ActionRun() { DistanceRan = 50  }
        }
    }
};

// serialize
var jsonSerialized = System.Text.Json.JsonSerializer.Serialize(testPolymorphism);
Console.WriteLine(jsonSerialized);

// deserialize
var clonePolymorphysm = System.Text.Json.JsonSerializer.Deserialize<TestPolymorphysm>(jsonSerialized);
Console.WriteLine(clonePolymorphysm);


// === MODELS ===

class TestPolymorphysm
{
    public List<Animal> Animals { get; set; } = new();
}

[JsonDerivedType(derivedType: typeof(Dog), typeDiscriminator: "foo1")]
[JsonDerivedType(derivedType: typeof(Fish), typeDiscriminator: "foo2")]
abstract class Animal
{
    public required string Id { get; set; }
    public required string Name { get; set; }
}

class Dog : Animal
{
    public required IAction Action { get; set; }
    public AnimalType ExtensionType => AnimalType.Dog;
}

class Fish : Animal
{
    public required IAction Action { get; set; }
    public AnimalType ExtensionType => AnimalType.Fish;
}

[JsonDerivedType(derivedType: typeof(ActionSwim), typeDiscriminator: "foo3")]
[JsonDerivedType(derivedType: typeof(ActionRun), typeDiscriminator: "foo4")]
interface IAction { }
class ActionSwim : IAction
{
    public required int DistanceSwam { get; set; }
}

class ActionRun : IAction
{
    public required int DistanceRan { get; set; }
}

public enum AnimalType
{
    Fish,
    Dog
}

Anyways this code works thanks to JsonDerivedType attributes but I am not sure why it works. Why is it that if I remove the typeDiscriminators foo1, foo2, foo3 and foo4 it does not work? I want to make sure I understand how it works before I use it.

2 Answers 2

4

The process is described in the documentation: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism?pivots=dotnet-7-0#polymorphic-type-discriminators

To enable polymorphic deserialization, you must specify a type discriminator for the derived class ... With the added metadata, specifically, the type discriminator, the serializer can serialize and deserialize the payload ... Serialization will emit JSON along with the type discriminator metadata

Essentially, the JsonDerivedTypeAttribute identifies supported derived types and adds the type discriminator $type as JSON metadata, which in turn instructs the serializer.

Sign up to request clarification or add additional context in comments.

2 Comments

Is it possible to specify a custom property name to use as the discriminator rather than $type. I am receiving a json object from a source I don't control that contains a discriminator string, it's just not $type
@rcbevans add attibute [JsonPolymorphic(TypeDiscriminatorPropertyName = "$discriminator")] learn.microsoft.com/en-us/dotnet/standard/serialization/…
2

Sorry I was not paying attention to the serialized object. It contains: "$type": "foo1",, "$type": "foo2", etc..

That's why the deserializer knows how to deserialize the object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.