Problem
PATCH and JSON Merge Patch operations need to distinguish three states for each field:
- absent — omit the field; leave the server value unchanged
- explicit null — send
null; clear the server value
- present — send a concrete value
Plain nullable types (T?) collapse absent and null into a single representation, so models cannot express partial updates faithfully. The initial serialization layer intentionally ships without a dedicated type for this; consumers must hand-roll converters or fall back to JsonNode.
Proposed direction
Introduce a three-state Optional<T> value type (absent / null / present) with:
- a
System.Text.Json converter, and
- source-generation support that omits absent members on write.
This is the .NET counterpart to the Tristate<T> container the Java and Python SDKs already provide.
Requirements & considerations
- Trim-safe and NativeAOT-compatible. The converter and the omit-on-absent behavior must work with source-generated
JsonSerializerContexts — no runtime reflection.
- Omission mechanism. Skipping an absent member cannot be expressed through
DefaultIgnoreCondition for a struct; it needs a JsonTypeInfo / ShouldSerialize modifier integrated with the source generator.
- Additive. This can land after the initial serialization work without changing existing public APIs.
- Ergonomics. Implicit conversion from
T, factory helpers (Optional.Of(value), Optional<T>.Absent), and clean pattern matching.
Out of scope (for now)
- Full RFC 7386 (JSON Merge Patch) document handling, unless we choose to layer it on top of
Optional<T>.
Problem
PATCH and JSON Merge Patch operations need to distinguish three states for each field:
null; clear the server valuePlain nullable types (
T?) collapse absent and null into a single representation, so models cannot express partial updates faithfully. The initial serialization layer intentionally ships without a dedicated type for this; consumers must hand-roll converters or fall back toJsonNode.Proposed direction
Introduce a three-state
Optional<T>value type (absent / null / present) with:System.Text.Jsonconverter, andThis is the .NET counterpart to the
Tristate<T>container the Java and Python SDKs already provide.Requirements & considerations
JsonSerializerContexts — no runtime reflection.DefaultIgnoreConditionfor a struct; it needs aJsonTypeInfo/ShouldSerializemodifier integrated with the source generator.T, factory helpers (Optional.Of(value),Optional<T>.Absent), and clean pattern matching.Out of scope (for now)
Optional<T>.