Search code examples
.netdeserializationsystem.text.json.net-8.0

.Net 7,8 System.Text.Json Deserialize Polymorphic Parameter


I have a class structure I can Serialize and Deserialize no problem. I have demonstrated it below in a contrived example

[JsonDerivedType(typeof(Apple),typeDiscriminator: "apple")]
public abstract class Fruit
{
    public Seed seed { get; }

    protected Fruit(Seed seed)
    {
        this.seed = seed;
    }
}

public sealed class Apple : Fruit
{
    [JsonConstructor]
    public Apple(Seed seed) : base(seed) { }
}

public sealed class AppleSeed : Seed
{
    [JsonConstructor]
    public AppleSeed() {}
}

[JsonDerivedType(typeof(AppleSeed),typeDiscriminator: "apple")]
public abstract class Seed { }

But I want the Apple constructor to require the type AppleSeed:

[JsonConstructor]
    public Apple(AppleSeed seed) : base(seed) { }

This serializes fine but fails to deserialize since the deserializer needs the base class info. I attempted to use generics to fix this but couldn't work it out. Is there a reliable way to deserialize polymorphic parameters using System.Text.Json without implementing a custom deserializer? Thanks


Solution

  • The problem with your public Apple(AppleSeed seed) : base(seed) { } constructor is explained in the documentation page Use immutable types and properties: Parameterized constructors:

    The parameter names of a parameterized constructor must match the property names and types.

    Since the constructor parameter type AppleSeed seed does not match the property type Seed seed, the constructor parameter cannot be used. Failing demo here.

    The easiest workaround is to hide the base type property with a new property of the same name and the required type:

    public sealed class Apple : Fruit
    {
        [JsonConstructor]
        public Apple(AppleSeed seed) : base(seed) { }
        
        public new AppleSeed seed => (AppleSeed)base.seed;
    }
    

    See also:

    Working fiddle here.