I have upgraded my project to netcore 3.0 and I am in the middle of refactoring a project to use the new nullable references types feature, but got stuck pretty quickly because of the following issue.
Lets say I consume a REST api which returns the following JSON:
{
"Name": "Volvo 240",
"Year": 1989
}
This api always returns the name/year, so they are non-nullable.
I would use this simple class for deserialization:
public class Car
{
public string Name {get; set;}
public int Year {get; set;}
}
And I would deserialize this to a Car
instance using the new System.Text.Json
var car = JsonSerializer.Deserialize<Car>(json);
This all works, but when enabling nullable reference types I get a warning in the Car
class that Name
is declared as non-nullable but can be null. I understand why I get this since it is possible to instantiate this object without initializing the Name
property.
So ideally Car
should look like this:
public class Car
{
public string Name { get; }
public int Year { get; }
public Car(string name, int year)
{
Name = name;
Year = year;
}
}
But this doesn't work because System.Text.Json
serializer doesn't support constructors with parameters.
So my question is: How would I declare Car
so that Name
is non-nullable and get it to work with System.Text.Json
without getting "non-nullable" warning?`
I don't want to make it nullable because I would have to do null-checks on basically everything when enabling nullable reference types, and since the REST API in my example says that they are always provided they shouldn't be nullable.
In a nullable aware context: A variable of a reference type T must be initialized with non-null, and may never be assigned a value that may be null . A variable of a reference type T? may be initialized with null or assigned null , but is required to be checked against null before de-referencing.
Although using nullable reference types can introduce its own set of problems, I still think it's beneficial because it helps you find potential bugs and allows you to better express your intent in the code. For new projects, I would recommend you enable the feature and do your best to write code without warnings.
Nullable reference types refers to a group of features introduced in C# 8.0 that you can use to minimize the likelihood that your code causes the runtime to throw System. NullReferenceException.
Ignore individual properties You can specify conditional exclusion by setting the [JsonIgnore] attribute's Condition property. The JsonIgnoreCondition enum provides the following options: Always - The property is always ignored. If no Condition is specified, this option is assumed.
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; }
}
Update
If you're on net5
, use the parameterized constructor support now offer as @langen points out. Else below can still be useful.
Original
Slightly 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
?? throw new ArgumentNullException(nameof(name));
Year = year;
}
}
Benefits being:
= null!;
on each property.Remaining downside with S.T.Json and nullable reference types:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With