Skip to content

Fix XML serialization for nullable value types#9736

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-xml-serialization-date-time-offset
Draft

Fix XML serialization for nullable value types#9736
Copilot wants to merge 3 commits intomainfrom
copilot/fix-xml-serialization-date-time-offset

Conversation

Copy link
Contributor

Copilot AI commented Feb 17, 2026

Generator was passing nullable value types directly to XML serialization methods instead of accessing their underlying .Value property, causing compilation errors.

Changes

  • Modified CreateXmlWriteValueStatement to call NullableStructValue() on values before passing to WriteStringValue and WriteBase64StringValue
  • Modified CreateXmlSerializeValueExpression to call NullableStructValue() before passing to CreateXmlSerializePrimitiveExpression, ensuring comprehensive coverage for all nullable value types
  • Applies to all nullable value types including DateTimeOffset?, TimeSpan?, int?, bool?, byte[]?, etc.
  • Added test CanSerializeCustomizedNullableDateTimeOffset to verify nullable properties customized via CodeGenMember attribute are correctly serialized

Example

Before:

if (Optional.IsDefined(PolicyStartsOn))
{
    writer.WriteStartElement("Start");
    writer.WriteStringValue(PolicyStartsOn, "O");  // Compile error: DateTimeOffset? != DateTimeOffset
    writer.WriteEndElement();
}

After:

if (Optional.IsDefined(PolicyStartsOn))
{
    writer.WriteStartElement("Start");
    writer.WriteStringValue(PolicyStartsOn.Value, "O");
    writer.WriteEndElement();
}

Non-nullable types unaffected - NullableStructValue() returns the value unchanged when not a nullable value type.

Original prompt

This section details on the original issue you should resolve

<issue_title>Fix Incorrect XML Serialization Code for Nullable DateTimeOffset Properties</issue_title>
<issue_description>See the storage library for an example. The Start and Expiry spec properties were customized to be DateTimeOffset. Our xml serialization code for this model is not correct, since we are not accessing the property's underlining value:

 if (Optional.IsDefined(PolicyStartsOn))
 {
     writer.WriteStartElement("Start");
     writer.WriteStringValue(PolicyStartsOn, "O");
     writer.WriteEndElement();
 }
 if (Optional.IsDefined(PolicyExpiresOn))
 {
     writer.WriteStartElement("Expiry");
     writer.WriteStringValue(PolicyExpiresOn, "O");
     writer.WriteEndElement();
 }

We should be calling writer.WriteStringValue(PolicyStartsOn.Value, "O");.

In general, this applies to all nullable types.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

- Modified CreateXmlWriteValueStatement to use NullableStructValue() for DateTimeOffset, TimeSpan, and byte[] types
- Added .Value accessor for nullable value types when calling WriteStringValue and WriteBase64StringValue
- Added unit tests for nullable DateTimeOffset and TimeSpan properties
- All existing tests pass (31 XML serialization tests)

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Feb 17, 2026
Copilot AI changed the title [WIP] Fix incorrect XML serialization code for nullable DateTimeOffset properties Fix XML serialization for nullable value types Feb 18, 2026
{
Type t when (t == typeof(DateTimeOffset) || t == typeof(TimeSpan)) && serializationFormat.ToFormatSpecifier() is string formatSpecifier
=> _xmlWriterSnippet.WriteStringValue(value, formatSpecifier),
=> _xmlWriterSnippet.WriteStringValue(value.NullableStructValue(valueType), formatSpecifier),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot since this can apply to other types aside from DateTimeOffset, and this method returns the ValueExpression if the type is not nullable, lets apply this across all types when we write the value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ed670a4. Applied NullableStructValue() to all value types by modifying CreateXmlSerializeValueExpression to call it before passing to CreateXmlSerializePrimitiveExpression. This ensures all nullable value types (int?, bool?, etc.) correctly access .Value.

Assert.IsTrue(methodBody.Contains("Duration.Value") && methodBody.Contains("WriteStringValue"),
$"Nullable TimeSpan property should be serialized with WriteStringValue and .Value accessor. Actual:\n{methodBody}");
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot lets also add an additional unit test to exercise the case where a datetime property is customized to be nullable via custom code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in ed670a4. Created test CanSerializeCustomizedNullableDateTimeOffset that verifies a DateTimeOffset property customized to be nullable via CodeGenMember attribute correctly uses .Value accessor in the generated XML serialization code.

…zed nullable DateTimeOffset

- Modified CreateXmlSerializeValueExpression to apply NullableStructValue before calling CreateXmlSerializePrimitiveExpression
- This ensures all nullable value types (not just DateTimeOffset/TimeSpan) correctly access .Value
- Added test CanSerializeCustomizedNullableDateTimeOffset for customized nullable properties
- All 1150 tests pass

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix Incorrect XML Serialization Code for Nullable DateTimeOffset Properties

2 participants