How to deal with nullable reference types with System.Text.Json? How to deal with nullable reference types with System.Text.Json? json json

How to deal with nullable reference types with System.Text.Json?


UPDATE

System.Text.Json for .NET 5 now supports parameterized constructors, so this should not be a problem anymore.

See https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-immutability?pivots=dotnet-5-0

Old answer below

After reading the msdocs I found out how I could solve this issue.

So until System.Text.Json cannot instantiate classes with parameters in their constructor, the Car class will have to look like this:

public class Car{    public string Name { get; set; } = default!;    public int Year { get; set; }}


UpdateIf you're on net5, use the parameterized constructor support now offer as @langen points out. Else below can still be useful.

OriginalSlightly alternative approach. System.Text.Json appears to have no problems using a private parameterless constructor. So you can at least do the following:

public class Car{    public string Name { get; set; }    public int Year { get; set; }    // For System.Text.Json deserialization only    #pragma warning disable CS8618 // Non-nullable field is uninitialized.    private Car() { }    #pragma warning restore CS8618    public Car(string name, int year)    {        Name = name;        Year = year;    }}

Benefits being:

  • Init of the object from your own code must be through the public ctor.
  • You don't need to do = null!; on each property.

Remaining downside with S.T.Json and nullable reference types:

  • S.T.Json still requires setters on the properties to actually set the values during deserialization. I tried with private ones and it's a no go, so we still can't get an immutable object...


Another option, for those who want to handle missing properties with meaningful exceptions:

using System;public class Car{    private string? name;    private int? year;    public string Name    {        get => this.name ?? throw new InvalidOperationException($"{nameof(this.Name)} was not set.");        set => this.name = value;    }    public int Year    {        get => this.year ?? throw new InvalidOperationException($"{nameof(this.Year)} was not set.");        set => this.year = value;    }}