Skip to content

Commit

Permalink
Fix Reflection-based to also look up the chain for missing property a…
Browse files Browse the repository at this point in the history
…ccessors.
  • Loading branch information
StephenMolloy committed May 20, 2021
1 parent 34926e2 commit d15494e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand All @@ -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!;
Expand All @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d15494e

Please sign in to comment.