using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; using System; using UnityEngine; namespace PashaBibko.Pacore { public static class ClassAttributeCache { private static Dictionary> AttributeCache { get; set; } public static ReadOnlyCollection GetAttributesOf() { return AttributeCache.TryGetValue(typeof(T), out List classes) ? classes.AsReadOnly() : throw new ArgumentException($"Attribute [{nameof(T)}] is not used by any classes"); } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] private static void ScanAllAssemblies() { /* Fetches all the class types in all loaded assemblies */ Type[] classes = AppDomain.CurrentDomain.GetAssemblies() // Assembly[] .SelectMany(assembly => assembly.GetTypes()) // IEnumerable .Where(type => type.IsClass && !type.IsAbstract) // IEnumerable .ToArray(); /* Allocates space for the cache */ AttributeCache = classes // Type[] .Where(type => typeof(Attribute).IsAssignableFrom(type)) // IEnumerable .ToDictionary ( keySelector: t => t, elementSelector: _ => new List() ); // Dictionary> /* Finds which attributes are attached to what classes */ HashSet seen = new(); foreach (Type current in classes) { /* Tracks the seen attributes */ seen.Clear(); foreach (object attr in current.GetCustomAttributes(inherit: true)) { seen.Add(attr.GetType()); } /* Adds the class type to each attribute in the dictionary */ foreach (Type type in seen) { AttributeCache[type].Add(current); } } } } }