using System;
using UnityEditor;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;
namespace EditorAttributes.Editor.Utility
{
public static class ReflectionUtility
{
public const BindingFlags BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy;
///
/// Finds a field inside a serialized object
///
/// The name of the field to search
/// The serialized property
/// The field info of the desired field
public static FieldInfo FindField(string fieldName, SerializedProperty property)
{
if (fieldName.Contains('.'))
return GetStaticMemberInfoFromPath(fieldName, MemberTypes.Field) as FieldInfo;
var fieldInfo = FindField(fieldName, property.serializedObject.targetObject);
// If the field null we try to see if its inside a serialized object
if (fieldInfo == null)
{
var serializedObjectType = GetNestedObjectType(property, out _);
if (serializedObjectType != null)
fieldInfo = serializedObjectType.GetField(fieldName, BINDING_FLAGS);
}
return fieldInfo;
}
internal static FieldInfo FindField(string fieldName, object targetObject) => FindMember(fieldName, targetObject?.GetType(), BINDING_FLAGS, MemberTypes.Field) as FieldInfo;
///
/// Finds a property inside a serialized object
///
/// The name of the property to search
/// The serialized property
/// The property info of the desired property
public static PropertyInfo FindProperty(string propertyName, SerializedProperty property)
{
if (propertyName.Contains('.'))
return GetStaticMemberInfoFromPath(propertyName, MemberTypes.Property) as PropertyInfo;
var propertyInfo = FindProperty(propertyName, property.serializedObject.targetObject);
// If the property null we try to see if its inside a serialized object
if (propertyInfo == null)
{
var serializedObjectType = GetNestedObjectType(property, out _);
if (serializedObjectType != null)
propertyInfo = serializedObjectType.GetProperty(propertyName, BINDING_FLAGS);
}
return propertyInfo;
}
internal static PropertyInfo FindProperty(string propertyName, object targetObject) => FindMember(propertyName, targetObject?.GetType(), BINDING_FLAGS, MemberTypes.Property) as PropertyInfo;
///
/// Finds a funciton inside a serialized object
///
/// The name of the function to search
/// The serialized property
/// The method info of the desired function
public static MethodInfo FindFunction(string functionName, SerializedProperty property)
{
if (functionName.Contains('.'))
return GetStaticMemberInfoFromPath(functionName, MemberTypes.Method) as MethodInfo;
MethodInfo methodInfo;
methodInfo = FindFunction(functionName, property.serializedObject.targetObject);
// If the method is null we try to see if its inside a serialized object
if (methodInfo == null)
{
var serializedObjectType = GetNestedObjectType(property, out _);
if (serializedObjectType == null)
return methodInfo;
try
{
methodInfo = serializedObjectType.GetMethod(functionName, BINDING_FLAGS);
}
catch (AmbiguousMatchException)
{
var functions = serializedObjectType.GetMethods();
foreach (var function in functions)
{
if (function.Name == functionName)
methodInfo = function;
}
}
}
return methodInfo;
}
internal static MethodInfo FindFunction(string functionName, object targetObject)
{
try
{
return FindMember(functionName, targetObject?.GetType(), BINDING_FLAGS, MemberTypes.Method) as MethodInfo;
}
catch (AmbiguousMatchException)
{
var functions = targetObject?.GetType().GetMethods();
foreach (var function in functions)
{
if (function.Name == functionName)
return function;
}
return null;
}
}
///
/// Finds a member from the target and it's inherited types
///
/// The name of the member to look for
/// The type to get the member from
/// The binding flags
/// The type of the member to look for. Only Field, Property and Method types are supported
/// The member info of the specified member type
public static MemberInfo FindMember(string memberName, Type targetType, BindingFlags bindingFlags, MemberTypes memberType)
{
MemberInfo memberInfo = null;
while (targetType != null)
{
switch (memberType)
{
case MemberTypes.Field:
memberInfo = targetType.GetField(memberName, bindingFlags);
break;
case MemberTypes.Property:
memberInfo = targetType.GetProperty(memberName, bindingFlags);
break;
case MemberTypes.Method:
memberInfo = targetType.GetMethod(memberName, bindingFlags);
break;
}
if (memberInfo != null)
return memberInfo;
targetType = targetType.BaseType;
}
return null;
}
///
/// Gets the info of a const or static member from the type specified in the path
///
/// The path on which to locate the member
/// The type of the member to look for. Only Field, Property and Method types are supported
/// The member info of the specified member type
public static MemberInfo GetStaticMemberInfoFromPath(string memberPath, MemberTypes memberTypes)
{
MemberInfo memberInfo = null;
string[] splitPath = memberPath.Split('.');
string typeNamespace = GetNamespaceString(splitPath);
string typeName = splitPath[^2];
string actualFieldName = splitPath[^1];
var matchingTypes = TypeCache.GetTypesDerivedFrom