Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix duplicate fields and buttons in the inspector when using inheritance #16

Merged
merged 1 commit into from
Feb 5, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 74 additions & 8 deletions Alchemy/Assets/Alchemy/Editor/Internal/ReflectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using UnityEngine;

namespace Alchemy.Editor.Internal
{
Expand Down Expand Up @@ -125,10 +126,33 @@ public static FieldInfo GetField(Type type, string name, BindingFlags bindingAtt
return info;
}

static IEnumerable<Type> EnumerateTypeHierarchy(Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}

class FieldInfoEqualityComparer : IEqualityComparer<FieldInfo>
{
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<FieldInfo> GetAllFieldsIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
{
if (type == null) return Enumerable.Empty<FieldInfo>();
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)
Expand All @@ -148,10 +172,24 @@ public static PropertyInfo GetProperty(Type type, string name, BindingFlags bind
return info;
}

class PropertyInfoEqualityComparer : IEqualityComparer<PropertyInfo>
{
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<PropertyInfo> GetAllPropertiesIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
{
if (type == null) return Enumerable.Empty<PropertyInfo>();
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)
Expand All @@ -171,10 +209,24 @@ public static MethodInfo GetMethod(Type type, string name, BindingFlags bindingA
return info;
}

class MethodInfoEqualityComparer : IEqualityComparer<MethodInfo>
{
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<MethodInfo> GetAllMethodsIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
{
if (type == null) return Enumerable.Empty<MethodInfo>();
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)
Expand Down Expand Up @@ -247,10 +299,24 @@ public static MemberInfo[] GetMembers(Type type, BindingFlags bindingAttr = Bind
}
}

class MemberInfoEqualityComparer : IEqualityComparer<MemberInfo>
{
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<MemberInfo> GetMembersIncludingBaseNonPublic(Type type, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
{
if (type == null) return Enumerable.Empty<MemberInfo>();
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)
Expand Down