Resolve hidden inspector members to the most-derived declaration
A keyed type that hides a base member with `new` offered two candidates for one name. The inspector now keeps the most-derived declaration, after dropping [IgnoreMember] ones, as the registry's own-member scan does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
4716c304ec
commit
5de49ebc60
2 changed files with 24 additions and 1 deletions
|
|
@ -520,7 +520,10 @@ namespace GameCult.Caching
|
|||
var candidates = type.GetMembers(Public)
|
||||
.Where(member => member is FieldInfo field && !field.IsLiteral ||
|
||||
member is PropertyInfo property && property.GetGetMethod() != null && property.GetIndexParameters().Length == 0)
|
||||
.Where(member => !member.IsDefined(typeof(IgnoreMemberAttribute), true));
|
||||
.Where(member => !member.IsDefined(typeof(IgnoreMemberAttribute), true))
|
||||
// A member hidden with `new` is its most-derived declaration, as the registry's own-member scan reads it.
|
||||
.GroupBy(member => member.Name)
|
||||
.Select(hides => hides.OrderByDescending(member => Ancestry(member.DeclaringType)).First());
|
||||
IEnumerable<(MemberInfo Member, int Slot)> slotted;
|
||||
if (type.IsDefined(typeof(CultDocumentAttribute), false))
|
||||
{
|
||||
|
|
@ -575,6 +578,8 @@ namespace GameCult.Caching
|
|||
private static CultInspectorShape Unsupported(Type type, string reason) =>
|
||||
new CultInspectorShape(type, CultInspectorValueKind.Unsupported) { Reason = reason };
|
||||
|
||||
private static int Ancestry(Type? type) => type == null ? 0 : 1 + Ancestry(type.BaseType);
|
||||
|
||||
private static Type TypeOf(MemberInfo member) => member is FieldInfo field ? field.FieldType : ((PropertyInfo)member).PropertyType;
|
||||
|
||||
private static bool Assignable(MemberInfo member, bool allowPrivate)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ namespace GameCult.Caching.Tests
|
|||
var id = Model().MembersOf(typeof(InspectFixed)).Single();
|
||||
Assert.That(id.IsAssignable, Is.False, "a get-only member its constructor fills cannot be assigned");
|
||||
Assert.That(id.IsReadOnly, Is.True);
|
||||
|
||||
var hidden = Model().MembersOf(typeof(InspectHider)).Single();
|
||||
Assert.That(hidden.Member.DeclaringType, Is.EqualTo(typeof(InspectHider)), "a `new` member is its most-derived declaration");
|
||||
Assert.That(hidden.ValueType, Is.EqualTo(typeof(string)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
@ -242,6 +246,20 @@ namespace GameCult.Caching.Tests
|
|||
public float Side;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class InspectHidden
|
||||
{
|
||||
[Key(0)]
|
||||
public int Value;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class InspectHider : InspectHidden
|
||||
{
|
||||
[Key(0)]
|
||||
public new string Value = string.Empty;
|
||||
}
|
||||
|
||||
public readonly record struct InspectPair(float x, float y);
|
||||
|
||||
public interface IFakeDrawer
|
||||
|
|
|
|||
Loading…
Reference in a new issue