From 30cc73dd77d0bb167dfdd0eb78f44f1383784072 Mon Sep 17 00:00:00 2001 From: PJBarczyk Date: Wed, 24 Jan 2024 18:42:08 +0100 Subject: [PATCH] Fix: Return only distinct members/fields from IncludingBaseNonPublic methods --- .../Editor/Internal/ReflectionHelper.cs | 82 +++++++++++++++++-- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/Alchemy/Assets/Alchemy/Editor/Internal/ReflectionHelper.cs b/Alchemy/Assets/Alchemy/Editor/Internal/ReflectionHelper.cs index 30df18c..9367eb6 100644 --- a/Alchemy/Assets/Alchemy/Editor/Internal/ReflectionHelper.cs +++ b/Alchemy/Assets/Alchemy/Editor/Internal/ReflectionHelper.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using UnityEngine; namespace Alchemy.Editor.Internal { @@ -125,10 +126,33 @@ public static FieldInfo GetField(Type type, string name, BindingFlags bindingAtt return info; } + static IEnumerable EnumerateTypeHierarchy(Type type) + { + while (type != null) + { + yield return type; + type = type.BaseType; + } + } + + class FieldInfoEqualityComparer : IEqualityComparer + { + public static readonly FieldInfoEqualityComparer Instance = new(); + + public bool Equals(FieldInfo x, FieldInfo y) + { + return x.Name == y.Name && x.DeclaringType == y.DeclaringType; + } + + public int GetHashCode(FieldInfo obj) + { + return HashCode.Combine(obj.Name, obj.DeclaringType); + } + } + static IEnumerable GetAllFieldsIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) { - if (type == null) return Enumerable.Empty(); - return type.GetFields(bindingAttr).Concat(GetAllFieldsIncludingBaseNonPublic(type.BaseType)); + return EnumerateTypeHierarchy(type).Reverse().SelectMany(t => t.GetFields(bindingAttr)).Distinct(FieldInfoEqualityComparer.Instance); } public static PropertyInfo GetProperty(Type type, string name, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, bool includingBaseNonPublic = false) @@ -148,10 +172,24 @@ public static PropertyInfo GetProperty(Type type, string name, BindingFlags bind return info; } + class PropertyInfoEqualityComparer : IEqualityComparer + { + public static readonly PropertyInfoEqualityComparer Instance = new(); + + public bool Equals(PropertyInfo x, PropertyInfo y) + { + return x.Name == y.Name && x.DeclaringType == y.DeclaringType; + } + + public int GetHashCode(PropertyInfo obj) + { + return HashCode.Combine(obj.Name, obj.DeclaringType); + } + } + static IEnumerable GetAllPropertiesIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) { - if (type == null) return Enumerable.Empty(); - return type.GetProperties(bindingAttr).Concat(GetAllPropertiesIncludingBaseNonPublic(type.BaseType)); + return EnumerateTypeHierarchy(type).Reverse().SelectMany(t => t.GetProperties(bindingAttr)).Distinct(PropertyInfoEqualityComparer.Instance); } public static MethodInfo GetMethod(Type type, string name, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, bool includingBaseNonPublic = false) @@ -171,10 +209,24 @@ public static MethodInfo GetMethod(Type type, string name, BindingFlags bindingA return info; } + class MethodInfoEqualityComparer : IEqualityComparer + { + public static readonly MethodInfoEqualityComparer Instance = new(); + + public bool Equals(MethodInfo x, MethodInfo y) + { + return x.Name == y.Name && x.DeclaringType == y.DeclaringType; + } + + public int GetHashCode(MethodInfo obj) + { + return HashCode.Combine(obj.Name, obj.DeclaringType); + } + } + static IEnumerable GetAllMethodsIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) { - if (type == null) return Enumerable.Empty(); - return type.GetMethods(bindingAttr).Concat(GetAllMethodsIncludingBaseNonPublic(type.BaseType)); + return EnumerateTypeHierarchy(type).Reverse().SelectMany(t => t.GetMethods(bindingAttr)).Distinct(MethodInfoEqualityComparer.Instance); } public static object GetValue(object target, string name, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, bool allowProperty = true, bool allowMethod = true) @@ -247,10 +299,24 @@ public static MemberInfo[] GetMembers(Type type, BindingFlags bindingAttr = Bind } } + class MemberInfoEqualityComparer : IEqualityComparer + { + public static readonly MemberInfoEqualityComparer Instance = new(); + + public bool Equals(MemberInfo x, MemberInfo y) + { + return x.Name == y.Name && x.DeclaringType == y.DeclaringType; + } + + public int GetHashCode(MemberInfo obj) + { + return HashCode.Combine(obj.Name, obj.DeclaringType); + } + } + static IEnumerable GetMembersIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) { - if (type == null) return Enumerable.Empty(); - return type.GetMembers(bindingAttr).Concat(GetMembersIncludingBaseNonPublic(type.BaseType)); + return EnumerateTypeHierarchy(type).Reverse().SelectMany(t => t.GetMembers(bindingAttr)).Distinct(MemberInfoEqualityComparer.Instance); } public static object Invoke(object target, string name, params object[] parameters)