Consider a simple case of trying to deserialize a record where some properties are missing:
#nullable enable
record Rec(int Age, Employee Employee); // Employee has a default constructor
var rec = JsonConvert.DeserializeObject<Rec>("{\"Age\":30}");
I get rec with Employee set to null without any compiler warning despite nullable enabled and have to manually set it using the default constructor.
Is there a way to tell DeserializeObject to try/use the default constructor for missing properties instead of setting them to null ?
There is an overload to DeserializeObject that allows you to pass in an array of JsonConverter which allows you to management the type conversion (from JObject) yourself. Alternatively you could also change the default JsonSerializerSettings to NOT allow nulls and manually handle the exception that is raised.
All of that would require a lot of boilerplate code but for simple default type instantiation, there is a
CustomCreationConverteryou can inherit from
class RecConverter : CustomCreationConverter<Rec>
{
public override Rec Create(Type objectType)
{
return new Rec ( 0, new Employee() { Name = "Custom" } );
}
}
Note that the default value of properties is usually defined in the declaration of the type itself.
DeserializeObject will first instantiate the object, and then if MissingMemberHandling is set to "Ignore", it only sets the properties that are available, the others will remain in their default initialized state, that is defined by the default constructor for that type, which may be defined through auto-property initialization syntax.
You could declare your class with default initialization for the properties that you require to be non-null:
public class Rec
{
public int Age { get;set; }
public Employee Employee { get;set; } = new Employee();
}
Similar rules apply for C#9 record, however DeserializeObject will call the relevant constructor that matches the arguments that are available from the JSON string, so you can use the verbose declaration syntax to achieve the same thing:
record Rec
{
public int Age { get;init; }
public Employee Employee { get;init; } = new Employee();
}
See this fiddle: https://dotnetfiddle.net/Dmpmn5