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 4e7b4e8e6e92d..eca311b4d31d9 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 @@ -637,7 +637,7 @@ private static ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate Get (Type, string) typeMemberNameTuple = (o.GetType(), memberName); if (!s_setMemberValueDelegateCache.TryGetValue(typeMemberNameTuple, out ReflectionXmlSerializationReaderHelper.SetMemberValueDelegate? result)) { - MemberInfo memberInfo = ReflectionXmlSerializationHelper.GetMember(o.GetType(), memberName); + MemberInfo memberInfo = ReflectionXmlSerializationHelper.GetEffectiveSetInfo(o.GetType(), memberName); Debug.Assert(memberInfo != null, "memberInfo could not be retrieved"); Type memberType; if (memberInfo is PropertyInfo propInfo) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs index 3ed294b0ac692..fe9ce0535a8d7 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs @@ -649,7 +649,7 @@ private void WriteStructMethod(StructMapping mapping, string n, string? ns, obje [RequiresUnreferencedCode("Calls GetType on object")] private object? GetMemberValue(object o, string memberName) { - MemberInfo memberInfo = ReflectionXmlSerializationHelper.GetMember(o.GetType(), memberName); + MemberInfo memberInfo = ReflectionXmlSerializationHelper.GetEffectiveGetInfo(o.GetType(), memberName); object? memberValue = GetMemberValue(o, memberInfo); return memberValue; } @@ -1356,7 +1356,7 @@ private enum WritePrimitiveMethodRequirement internal static class ReflectionXmlSerializationHelper { [RequiresUnreferencedCode("Reflects over base members")] - public static MemberInfo GetMember(Type declaringType, string memberName) + public static MemberInfo? GetMember(Type declaringType, string memberName, bool throwOnNotFound) { MemberInfo[] memberInfos = declaringType.GetMember(memberName); if (memberInfos == null || memberInfos.Length == 0) @@ -1377,7 +1377,11 @@ public static MemberInfo GetMember(Type declaringType, string memberName) if (!foundMatchedMember) { - throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, $"Could not find member named {memberName} of type {declaringType}")); + if (throwOnNotFound) + { + throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, $"Could not find member named {memberName} of type {declaringType}")); + } + return null; } declaringType = currentType!; @@ -1398,5 +1402,59 @@ public static MemberInfo GetMember(Type declaringType, string memberName) return memberInfo; } + + public static MemberInfo GetEffectiveGetInfo(Type declaringType, string memberName) + { + MemberInfo memberInfo = GetMember(declaringType, memberName, true)!; + + // For properties, we might have a PropertyInfo that does not have a valid + // getter at this level of inheritance. If that's the case, we need to look + // up the chain to find the right PropertyInfo for the getter. + if (memberInfo is PropertyInfo propInfo && propInfo.GetMethod == null) + { + var parent = declaringType.BaseType; + + while (parent != null) + { + var mi = GetMember(parent, memberName, false); + + if (mi is PropertyInfo pi && pi.GetMethod != null && pi.PropertyType == propInfo.PropertyType) + { + return pi; + } + + parent = parent.BaseType; + } + } + + return memberInfo; + } + + public static MemberInfo GetEffectiveSetInfo(Type declaringType, string memberName) + { + MemberInfo memberInfo = GetMember(declaringType, memberName, true)!; + + // For properties, we might have a PropertyInfo that does not have a valid + // setter at this level of inheritance. If that's the case, we need to look + // up the chain to find the right PropertyInfo for the setter. + if (memberInfo is PropertyInfo propInfo && propInfo.SetMethod == null) + { + var parent = declaringType.BaseType; + + while (parent != null) + { + var mi = GetMember(parent, memberName, false); + + if (mi is PropertyInfo pi && pi.SetMethod != null && pi.PropertyType == propInfo.PropertyType) + { + return pi; + } + + parent = parent.BaseType; + } + } + + return memberInfo; + } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs index 8612561f1455e..5e0665489f429 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs @@ -1219,8 +1219,9 @@ private static bool ShouldBeReplaced( replacedInfo = info; if (replacedInfo != memberInfoToBeReplaced) { - // The property is a match. Check to see if the derived property - // has a getter that is useable for serialization. + // The property name is a match. It might be an override, or + // it might be hiding. Either way, check to see if the derived + // property has a getter that is useable for serialization. if (info.GetMethod != null && !info.GetMethod!.IsPublic && memberInfoToBeReplaced is PropertyInfo && ((PropertyInfo)memberInfoToBeReplaced).GetMethod!.IsPublic