Overview
ℹ️ Important
Availability: .NET 8
When deserializing JSON, you can either replace or populate .NET properties and fields.
Setting the behavior
This is done by setting the JsonObjectCreationHandling
attribute to JsonObjectCreationHandling.Populate
. This attribute can be set to one
setting at the type level and another setting at the property level to override the behavior inherited from the type:
// Type-level preference is Populate.
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class B
{
// For this property only, use Replace behavior.
[JsonObjectCreationHandling(JsonObjectCreationHandling.Replace)]
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
The setting can also be applied globally by setting JsonSerializerOptions.PreferredObjectCreationHandling
:
var options = new JsonSerializerOptions
{
PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate
};
Replace (default) behavior
Consider this code:
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
After the above JSON is deserialized onto A
:
Numbers1
will still have values 1, 2, 3 (it’s a read-only property).Numbers2
will have a new list allocated and the values from the JSON added. Its values will be 4, 5, 6.
Populate behavior
This behavior modifies (populates) properties and fields instead of replacing them. This is also true for read-only properties.
For a property that is an object with properties, the object is reused without clearing. Its mutable properties are updated to the JSON values.
Example: collection type properties
For collection type properties, the object is reused without clearing. Any prepopulated elements in the collection will remain:
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
After the above JSON is deserialized onto A
: Numbers1
and Numbers2
will have values 1, 2, 3, 4, 5, 6.
Example: Struct properties
For a struct type property, the object is not reused (since it’s a value type). For its mutable properties, any existing values are kept and new values from the JSON are added:
C? c = JsonSerializer.Deserialize<C>("""{"S1": {"Value2": 5}}""");
class C
{
public C()
{
_s1 = new S
{
Value1 = 10
};
}
private S _s1;
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public S S1
{
get { return _s1; }
set { _s1 = value; }
}
}
struct S
{
public int Value1 { get; set; }
public int Value2 { get; set; }
}