How it works
Serialization can omit members under a configured condition. WhenWritingNull omits null-valued properties but keeps ordinary value-type defaults such as zero and false. WhenWritingDefault also omits those default values. The same in-memory Item therefore produces two different JSON object shapes.
The first output preserves Count zero and Enabled false while omitting Name. The second output is empty because all three properties hold their type's default value. A smaller payload is not automatically a more faithful payload: an explicit false may communicate a deliberate user choice that an absent property would not communicate.
The receiving contract decides whether omission is safe. In a full replacement representation, an omitted default may be reconstructed harmlessly. In a partial update, omission might mean leave the previous value unchanged, so removing an explicit zero or false could change the operation's meaning. Write and read policies must be designed together.
Do not confuse an output-omission condition with input validation. The setting controls what is written; it does not prove that a deserialized object satisfies a domain rule or that a caller supplied every meaningful property. Presence-sensitive input may need a separate model or explicit tracking.
Practice by changing Count to one, Enabled to true, and Name to an empty string one at a time. Predict which properties appear under each option. Explain why an empty string is not the default string reference value even though an application might consider it semantically empty.
Finally, design two examples: a compact full-state export and a partial-update request. Decide separately whether default omission belongs in each contract. Tests should compare the meaningful presence of properties rather than relying only on payload length, because the most important difference may be whether a receiver interprets an absent field as a command to preserve older state.
A working example
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
var item = new Item { Name = null, Count = 0, Enabled = false };
var nulls = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
var defaults = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault };
Console.WriteLine(JsonSerializer.Serialize(item, nulls));
Console.WriteLine(JsonSerializer.Serialize(item, defaults));
class Item {
public string? Name { get; set; }
public int Count { get; set; }
public bool Enabled { get; set; }
}
Expected output
{"Count":0,"Enabled":false}
{}WhenWritingDefault includes value-type defaults, not only null references.