Skip to content
This repository has been archived by the owner on Apr 10, 2024. It is now read-only.

Commit

Permalink
Add GetMembersRecursive
Browse files Browse the repository at this point in the history
  • Loading branch information
uurha committed Mar 2, 2024
1 parent a16b3e8 commit b513623
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,14 @@ public static bool GetTypeFromManagedReferenceFullTypeName(string managedReferen

public static CachedFieldInfo GetFieldInfoFromPropertyPath(Type type, string propertyPath)
{
var arrayElement = ArrayDataWithIndexRegexAny.IsMatch(propertyPath);
propertyPath = ArrayDataWithIndexRegex.Replace(propertyPath, ArrayElementDotName);
var cache = new CacheKey(type, propertyPath);

if (FieldInfoFromPropertyPathCache.TryGetValue(cache, out var fieldInfoCache))
{
return fieldInfoCache;
}

var arrayElement = ArrayDataWithIndexRegexAny.IsMatch(propertyPath);
propertyPath = ArrayDataWithIndexRegex.Replace(propertyPath, ArrayElementDotName);

if (FieldInfoFromPropertyPath(propertyPath, ref type, out var fieldInfo))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"name": "BetterExtensions.Runtime",
"rootNamespace": "Better.Extensions.Runtime",
"references": [],
"references": [
"GUID:01df13aca8d01e24a911bcc3e8277031"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
Expand Down
76 changes: 73 additions & 3 deletions Assets/BetterExtensions/Runtime/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Better.Internal.Core.Runtime;
using UnityObject = UnityEngine.Object;

namespace Better.Extensions.Runtime
Expand Down Expand Up @@ -136,7 +137,7 @@ public static IEnumerable<Type> GetAllInheritedTypesWithoutUnityObject(this Type

return self.GetAllInheritedTypes(unityObjectType);
}

public static bool IsAnonymous(this Type type)
{
if (type.IsClass && type.IsSealed && type.Attributes.HasFlag(TypeAttributes.NotPublic))
Expand All @@ -150,7 +151,7 @@ public static bool IsAnonymous(this Type type)

return false;
}

public static IEnumerable<Type> GetAllInheritedTypesOfRawGeneric(this Type self)
{
if (self == null)
Expand Down Expand Up @@ -233,7 +234,7 @@ public static bool IsSubclassOfRawGeneric(this Type self, Type genericType)

return false;
}

public static bool IsSubclassOfAnyRawGeneric(this Type self, IEnumerable<Type> genericTypes)
{
if (self == null)
Expand Down Expand Up @@ -289,5 +290,74 @@ public static bool IsNullable(this Type self)

return Nullable.GetUnderlyingType(self) != null;
}

public static IEnumerable<MemberInfo> GetMembersRecursive(this Type type)
{
if (type == null)
{
DebugUtility.LogException<ArgumentNullException>(nameof(type));
return Enumerable.Empty<MemberInfo>();
}

var members = new HashSet<MemberInfo>(new MemberInfoComparer());

const BindingFlags methodFlags = Defines.MethodFlags & ~BindingFlags.DeclaredOnly;
do
{
// If the type is a constructed generic type, get the members of the generic type definition
var typeToReflect = type.IsGenericType && !type.IsGenericTypeDefinition ? type.GetGenericTypeDefinition() : type;

foreach (var member in typeToReflect.GetMembers(methodFlags))
{
// For generic classes, convert members back to the constructed type
var memberToAdd = type.IsGenericType && !type.IsGenericTypeDefinition
? ConvertToConstructedGenericType(member, type)
: member;

if (memberToAdd != null)
{
members.Add(memberToAdd);
}
}

type = type.BaseType;
} while (type != null); // Continue until you reach the top of the inheritance hierarchy

return members;
}

private static MemberInfo ConvertToConstructedGenericType(MemberInfo memberInfo, Type constructedType)
{
// Ensure the member's declaring type is a generic type definition
if (memberInfo.DeclaringType != null && memberInfo.DeclaringType.IsGenericTypeDefinition)
{
var members = constructedType.GetMember(memberInfo.Name);
return members.FirstOrDefault();
}

// Return the original memberInfo if it's not a property of a generic type definition or doesn't need to be constructed
return memberInfo;
}

public static MemberInfo GetMemberByNameRecursive(this Type type, string memberName)
{
if (type == null)
{
DebugUtility.LogException<ArgumentNullException>(nameof(type));
return null;
}

if (string.IsNullOrEmpty(memberName))
{
DebugUtility.LogException<ArgumentException>(nameof(memberName));
return null;
}

var allMembers = GetMembersRecursive(type);

// Use LINQ to find the member by name. This assumes you want the first match if there are multiple members with the same name (overloads).
// If you expect overloads and want to handle them differently, you might need a more complex approach.
return allMembers.FirstOrDefault(m => m.Name == memberName);
}
}
}
3 changes: 3 additions & 0 deletions Assets/BetterExtensions/Runtime/Helpers/Compares.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Reflection;

namespace Better.Extensions.Runtime
{
internal class MemberInfoComparer : IEqualityComparer<MemberInfo>
{
public bool Equals(MemberInfo x, MemberInfo y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;
return x.Name == y.Name && x.DeclaringType == y.DeclaringType;
}

public int GetHashCode(MemberInfo obj)
{
unchecked
{
var hashCode = obj.Name.GetHashCode();
if (obj.DeclaringType != null) hashCode = (hashCode * 397) ^ obj.DeclaringType.GetHashCode();
return hashCode;
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Assets/BetterExtensions/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.uurha.betterextensions",
"displayName": "Better Extensions",
"version": "1.5.7",
"version": "1.5.8",
"unity": "2021.3",
"description": "Unity extensions, serialize extension, async extension, string extension and UI extensions",
"dependencies": {
Expand Down

0 comments on commit b513623

Please sign in to comment.