diff --git a/.agents/skills/polyxml-codegen-workflow/SKILL.md b/.agents/skills/polyxml-codegen-workflow/SKILL.md index 0467fb9..02179e0 100644 --- a/.agents/skills/polyxml-codegen-workflow/SKILL.md +++ b/.agents/skills/polyxml-codegen-workflow/SKILL.md @@ -815,3 +815,9 @@ Jackson 3 sorts properties alphabetically by default. Emit `@JsonPropertyOrder` from flattened schema fields for its struct models, including inherited fields, or valid reads can produce XSD-invalid XML on writes. The Spring fixture checks returned XML against the source XSD independently using the JDK validator. + +C# positional record properties named Equals/GetHashCode/ToString collide with +synthesized methods (UCI QueryPET's Equals field exposed CS8866). Suffix their +identifiers with Value before applying per-struct uniqueness; preserve original +XML names. The particle wire round-trip test covers these names and an explicit +EqualsValue collision in both record and mutable-class modes. diff --git a/crates/polyxml-core/src/codegen/csharp/mod.rs b/crates/polyxml-core/src/codegen/csharp/mod.rs index e9b7501..e4e9a7d 100644 --- a/crates/polyxml-core/src/codegen/csharp/mod.rs +++ b/crates/polyxml-core/src/codegen/csharp/mod.rs @@ -114,6 +114,12 @@ pub fn to_csharp_property_name(raw: &str, enclosing_type: Option<&str>) -> Strin }; let sanitized = sanitize_keyword(&safe, "csharp"); + // Positional record members cannot shadow the synthesized equality methods. + let sanitized = if matches!(sanitized.as_str(), "Equals" | "GetHashCode" | "ToString") { + format!("{sanitized}Value") + } else { + sanitized + }; if let Some(enclosing) = enclosing_type { if sanitized == enclosing || sanitized.trim_start_matches('@') == enclosing { return format!("{}Value", sanitized); diff --git a/crates/polyxml-core/tests/test_csharp_codegen.rs b/crates/polyxml-core/tests/test_csharp_codegen.rs index e3064e8..91140a9 100644 --- a/crates/polyxml-core/tests/test_csharp_codegen.rs +++ b/crates/polyxml-core/tests/test_csharp_codegen.rs @@ -79,6 +79,7 @@ static DOTNET_LOCK: Mutex<()> = Mutex::new(()); #[test] fn particle_wire_structure_round_trips() { for (schema, root, documents) in [ + (r#""#, "Query", vec!["abcd"]), (include_str!("../../../research/fixtures/nested_sequence_choice.xsd"), "Root", vec!["AB", "C"]), (include_str!("../../../research/fixtures/repeated_sequence.xsd"), "Root", vec!["A1B1A2B2"]), (include_str!("../../../research/fixtures/substitution_group.xsd"), "Portfolio", vec!["A1B1A2"]),