diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs index 0c08561ba20ced..1418b7342558d8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs @@ -1139,13 +1139,10 @@ private static bool IsWildcard(SpecialMapping mapping) Type collectionType = memberMapping.TypeDesc!.Type!; o = ReflectionCreateObject(memberMapping.TypeDesc.Type!); - if (memberMapping.ChoiceIdentifier != null) - { - // https://github.com/dotnet/runtime/issues/1400: - // To Support ArrayMapping Types Having ChoiceIdentifier - throw new NotImplementedException("memberMapping.ChoiceIdentifier != null"); - } - + // When this array is the value of a member that carries an [XmlChoiceIdentifier] + // (e.g. one of the choice element types is itself an array), the parallel choice + // value is recorded by the calling WriteElement against the owning member after + // this method returns, so no additional choice handling is needed here. var arrayMember = new Member(memberMapping); arrayMember.Collection = new CollectionMember(); arrayMember.ArraySource = arrayMember.Collection.Add; diff --git a/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs b/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs index 1451e7407d8148..35a2d1a01ae9e8 100644 --- a/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs +++ b/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs @@ -1927,6 +1927,33 @@ public static void Xml_TypeWithArrayPropertyHavingComplexChoice() Assert.True(Enumerable.SequenceEqual(value.ManyChoices, actual.ManyChoices)); } + [Fact] + public static void Xml_TypeWithArrayLikeChoiceElement() + { + // Exercises an [XmlChoiceIdentifier] member where one of the choice element types is + // itself an array, so that element's mapping is an ArrayMapping. Deserializing such a + // value drives the reflection-based reader's array-reading path while the owning member + // carries a choice identifier. + var value = new TypeWithArrayLikeChoiceElement() + { + ManyChoices = new object[] { "hello", new int[] { 1, 2, 3 } }, + ChoiceArray = new ArrayLikeChoice[] { ArrayLikeChoice.Word, ArrayLikeChoice.Numbers } + }; + + var actual = SerializeAndDeserialize(value, WithXmlHeader("\r\n hello\r\n \r\n 1\r\n 2\r\n 3\r\n \r\n")); + + Assert.NotNull(actual); + Assert.NotNull(actual.ManyChoices); + Assert.Equal(2, actual.ManyChoices.Length); + Assert.Equal("hello", actual.ManyChoices[0]); + int[] numbers = Assert.IsType(actual.ManyChoices[1]); + Assert.Equal(new int[] { 1, 2, 3 }, numbers); + + // The [XmlIgnore] choice array is populated during deserialization to mirror, per item, + // which element each value was read from. + Assert.Equal(new ArrayLikeChoice[] { ArrayLikeChoice.Word, ArrayLikeChoice.Numbers }, actual.ChoiceArray); + } + [Fact] public static void XML_TypeWithTypeNameInXmlTypeAttribute_WithValue() { @@ -3272,3 +3299,23 @@ private static string GuessCachedName(string name) throw new ArgumentException($"Cannot guess cached field name from switch name '{name}'"); } } + +public class TypeWithArrayLikeChoiceElement +{ + // One of the choice element types (Numbers) is an array, so its element mapping is an + // ArrayMapping. Each item in ManyChoices is matched to an item in ChoiceArray. + [XmlChoiceIdentifier("ChoiceArray")] + [XmlElement("Word", typeof(string))] + [XmlElement("Numbers", typeof(int[]))] + public object[] ManyChoices; + + [XmlIgnore] + public ArrayLikeChoice[] ChoiceArray; +} + +public enum ArrayLikeChoice +{ + None, + Word, + Numbers +}