Fix XmlSerializer UnknownAttribute perf regression - #131908
Draft
StephenMolloy wants to merge 1 commit into
Draft
Conversation
… performance - Removed redundant calls to HandleUnknownAttributes in ReflectionXmlSerializationReader. - Consolidated attribute handling logic to avoid unnecessary attribute enumeration for built-in typed members. - Introduced AttributeTrackingXmlReader to track attribute operations during deserialization. - Added unit tests to verify that attributes are not enumerated when not needed and to ensure correct behavior with stray attributes.
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts XmlSerializer deserialization for primitive/array/collection-mapped elements to reduce unnecessary attribute walking and to align unknown-attribute surfacing behavior more closely with other mapping paths. It also extends the test suite to validate attribute enumeration behavior (including xsi:nil handling) using a tracking XmlReader.
Changes:
- Updated reflection-based deserialization to skip unknown-attribute enumeration unless there are unknown-node/attribute subscribers and the element actually has attributes.
- Updated generated-reader code emission (C# + IL) to avoid
MoveToNextAttributewhenReader.HasAttributesis false, and to ensure nil-handling paths don’t surface attributes. - Added tests and a tracking
XmlReaderwrapper to assert attribute enumeration / lookup behavior.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs | Adds attribute-enumeration tracking tests and an XmlReader wrapper to validate the new behavior. |
| src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs | Adjusts emitted IL to gate attribute enumeration behind Reader.HasAttributes and reorders calls around ReadNull. |
| src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs | Adds an internal “has subscribers” helper and updates generated-source emission to check Reader.HasAttributes before enumerating. |
| src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs | Refactors unknown-attribute handling to return early when there are no relevant event subscribers and/or no attributes. |
Comment on lines
4616
to
4621
| private void WriteHandleUnknownAttributes() | ||
| { | ||
| // When the element is marked xsi:nil, the nil marker (and the element itself) is consumed | ||
| // by the following ReadNull() call, so its attributes must not be surfaced as unknown. This | ||
| // also matches the struct path, where a nil element returns before its attributes are read. | ||
| Writer.WriteLine("if (!GetNullAttr()) {"); | ||
| Writer.WriteLine("if (Reader.HasAttributes) {"); | ||
| Writer.Indent++; | ||
| Writer.WriteLine("while (Reader.MoveToNextAttribute()) {"); | ||
| Writer.Indent++; |
Comment on lines
+2209
to
+2211
| [Fact] | ||
| public static void XmlBuiltInTypedMembersWithAttributesWithoutSubscribers() | ||
| { |
| } | ||
| } | ||
|
|
||
| public override string? GetAttribute(string name) => _reader.GetAttribute(name); |
This was referenced Aug 6, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request refactors how unknown XML attributes are handled during XML deserialization, specifically for elements mapped to built-in primitive types and arrays in the
XmlSerializer. The main change is to avoid enumerating attributes (i.e., callingMoveToNextAttribute) unless there are subscribers to unknown node or attribute events, improving performance and aligning behavior with struct deserialization. The PR also updates related tests to verify the new behavior.Attribute Handling Logic Updates:
HandleUnknownAttributesinReflectionXmlSerializationReaderand related codegen to only enumerate attributes if there are subscribers to unknown node or attribute events and the element has attributes, instead of always enumerating unless the element is markedxsi:nil. [1] [2] [3] [4] [5]XmlSerializationReader.csandXmlSerializationReaderILGen.cs) to match the new logic, ensuring consistency between runtime and generated serializers. [1] [2] [3] [4] [5] [6] [7] [8]Test Improvements:
XmlBuiltInTypedMembersWithoutAttributesAvoidAttributeEnumerationandXmlBuiltInTypedMembersWithAttributesWithoutSubscribers) to verify that attribute enumeration is avoided when there are no event subscribers, and that attributes are only enumerated when subscribers are present.AttributeTrackingXmlReaderand assert the number of attribute enumeration operations, confirming the new logic is correctly applied. [1] [2] [3] [4]Behavioral Consistency:
xsi:nildo not surface their attributes as unknown, maintaining consistency with struct deserialization. [1] [2] [3] [4]These changes improve performance and correctness by reducing unnecessary attribute enumeration and aligning the handling of unknown attributes across different mapping types.
Fixes #131813