using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; namespace TriInspector.Utilities { internal static class TriReflectionUtilities { private static readonly Dictionary> AttributesCache = new Dictionary>(); private static IReadOnlyList _assemblies; private static IReadOnlyList _allNonAbstractTypesBackingField; public static IReadOnlyList Assemblies { get { if (_assemblies == null) { _assemblies = AppDomain.CurrentDomain.GetAssemblies(); } return _assemblies; } } public static IReadOnlyList AllNonAbstractTypes { get { if (_allNonAbstractTypesBackingField == null) { _allNonAbstractTypesBackingField = Assemblies .SelectMany(asm => { try { return asm.GetTypes(); } catch (ReflectionTypeLoadException) { return Array.Empty(); } }) .Where(type => !type.IsAbstract) .ToList(); } return _allNonAbstractTypesBackingField; } } public static IReadOnlyList GetAttributesCached(Type type) { if (AttributesCache.TryGetValue(type, out var attributes)) { return attributes; } return AttributesCache[type] = type.GetCustomAttributes().ToList(); } public static IReadOnlyList GetCustomAttributes(this Assembly asm) { return asm.GetCustomAttributes(typeof(T)).Cast().ToList(); } public static IReadOnlyList GetAllInstanceFieldsInDeclarationOrder(Type type) { const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; return GetAllMembersInDeclarationOrder(type, it => it.GetFields(flags)); } public static IReadOnlyList GetAllInstancePropertiesInDeclarationOrder(Type type) { const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; return GetAllMembersInDeclarationOrder(type, it => it.GetProperties(flags)); } public static IReadOnlyList GetAllInstanceMethodsInDeclarationOrder(Type type) { const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; return GetAllMembersInDeclarationOrder(type, it => it.GetMethods(flags)); } public static bool IsArrayOrList(Type type, out Type elementType) { if (type.IsArray) { elementType = type.GetElementType(); return true; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { elementType = type.GetGenericArguments().Single(); return true; } elementType = null; return false; } public static Type GetUnityEditorTypeByFullName(string name) { return GetTypeByFullName(name, typeof(Editor).Assembly); } public static Type GetTypeByFullName(string name, Assembly assembly) { return assembly .GetTypes() .Single(it => it.FullName == name); } private static IReadOnlyList GetAllMembersInDeclarationOrder( Type type, Func select) where T : MemberInfo { var result = new List(); var typeTree = new Stack(); while (type != null) { typeTree.Push(type); type = type.BaseType; } foreach (var t in typeTree) { var items = select(t); result.AddRange(items); } return result; } } }