| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Reflection;
- using AttributeGroup = System.Collections.Generic.Dictionary<
- System.Type,
- com.bbbirder.DirectRetrieveAttribute[]
- >;
- //using TypeSet = System.Collections.Generic.HashSet<System.Type>;
- namespace com.bbbirder
- {
- public static class Retriever
- {
- static BindingFlags bindingFlags = 0
- | BindingFlags.Instance
- | BindingFlags.Public
- | BindingFlags.NonPublic
- | BindingFlags.Static
- | BindingFlags.DeclaredOnly
- ;
- static WeakHolder<AttributeGroup> m_attrLut;
- static WeakHolder<AttributeGroup> attrLut => m_attrLut ??= new(() =>
- {
- // var al = AppDomain.CurrentDomain.GetAssemblies()
- // .Where(a => a.IsDefined(typeof(GeneratedDirectRetrieveAttribute),false))
- // .SelectMany(a => a.GetCustomAttributes<GeneratedDirectRetrieveAttribute>())
- // .Select(a => a.type)
- // .Distinct()
- // .ToArray();
- return AppDomain.CurrentDomain.GetAssemblies()
- .Where(a => a.IsDefined(typeof(GeneratedDirectRetrieveAttribute)))
- .SelectMany(a => GetAllAttributes<DirectRetrieveAttribute>(a))
- .GroupBy(a => a.GetType() ?? typeof(object), a => a)
- .ToDictionary(e => e.Key, e => e.ToArray());
- });
- static WeakHolder<Type[]> m_typeSet;
- static WeakHolder<Type[]> typeSet => m_typeSet ??= new(() =>
- {
- return AppDomain.CurrentDomain.GetAssemblies()
- .Where(a => a.IsDefined(typeof(GeneratedDirectRetrieveAttribute), false))
- .SelectMany(a => a.GetCustomAttributes<GeneratedDirectRetrieveAttribute>())
- .Select(a => a.type)
- .Distinct()
- .ToArray();
- });
- /// <summary>
- /// Retrieve attributes of type T in all loaded assemblies
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- public static T[] GetAllAttributes<T>() where T : DirectRetrieveAttribute
- {
- return GetAllAttributes(typeof(T)).OfType<T>().ToArray();
- }
- /// <summary>
- /// Retrieve attributes of target type in all loaded assemblies
- /// </summary>
- /// <param name="attributeType"></param>
- /// <returns></returns>
- public static DirectRetrieveAttribute[] GetAllAttributes(Type attributeType)
- {
- #if DEBUG
- CheckAttribute(attributeType);
- #endif
- return attrLut.Value.ToArray()
- .Where(a => attributeType.IsAssignableFrom(a.Key))
- .SelectMany(a => a.Value)
- .ToArray()
- ;
- }
- /// <summary>
- /// Retrieve attributes of target type in a specific assembly
- /// </summary>
- /// <param name="attributeType"></param>
- /// <param name="assembly"></param>
- /// <returns></returns>
- public static DirectRetrieveAttribute[] GetAllAttributes(Type attributeType, Assembly assembly)
- {
- #if DEBUG
- CheckAttribute(attributeType);
- #endif
- return assembly.GetCustomAttributes<GeneratedDirectRetrieveAttribute>()
- .SelectMany(a =>
- {
- var targetType = a.type;
- IEnumerable<DirectRetrieveAttribute> result;
- if (a.HasMemberName)
- {
- result = targetType.GetMember(a.memberName, bindingFlags).SelectMany(
- member => member.GetCustomAttributes(attributeType, false).Select(
- ca => SetAttributeValue(ca as DirectRetrieveAttribute, member)
- )
- );
- }
- else
- {
- result = targetType.GetCustomAttributes(attributeType, false).Select(
- ca => SetAttributeValue(ca as DirectRetrieveAttribute, targetType)
- );
- }
- if (result.Count() == 0)
- {
- throw new("cannot find attribute but the assembly metadata preset, please check your script-strip setting");
- }
- return result;
- })
- .ToArray();
- }
- /// <summary>
- /// Retrieve attributes of type T in a specific assembly
- /// </summary>
- /// <param name="assembly"></param>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- public static T[] GetAllAttributes<T>(Assembly assembly) where T : DirectRetrieveAttribute
- {
- var attrType = typeof(T);
- return assembly.GetCustomAttributes<GeneratedDirectRetrieveAttribute>()
- .SelectMany(a =>
- {
- var targetType = a.type;
- if (a.HasMemberName)
- return targetType.GetMember(a.memberName, bindingFlags).SelectMany(
- member => member.GetCustomAttributes<T>(false).Select(
- ca => SetAttributeValue(ca, member)
- )
- );
- else
- return targetType.GetCustomAttributes<T>(false).Select(
- ca => SetAttributeValue(ca, targetType)
- );
- })
- .ToArray();
- }
- /// <summary>
- /// Retrieve all subclasses that inherit from the target type
- /// </summary>
- /// <param name="baseType"></param>
- /// <returns></returns>
- public static Type[] GetAllSubtypes(Type baseType)
- {
- #if DEBUG
- CheckBasetype(baseType);
- #endif
- if (baseType.IsGenericTypeDefinition)
- {
- return typeSet.Value
- .Where(a => a != baseType)
- .Where(a => GetTypesTowardsBase(a).Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == baseType)
- || a.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == baseType))
- .ToArray()
- ;
- }
- else
- {
- return typeSet.Value
- .Where(a => a != baseType && baseType.IsAssignableFrom(a))
- .ToArray()
- ;
- }
- static IEnumerable<Type> GetTypesTowardsBase(Type type)
- {
- while (type != null)
- {
- yield return type;
- type = type.BaseType;
- }
- }
- }
- /// <summary>
- /// Retrieve all subclasses that inherit from the target type
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- public static Type[] GetAllSubtypes<T>()
- {
- return GetAllSubtypes(typeof(T));
- }
- /// <summary>
- /// Retrieve all subclasses that inherit from the target type in a specific assembly
- /// </summary>
- /// <param name="assembly"></param>
- /// <typeparam name="T"></typeparam>
- /// <returns></returns>
- public static Type[] GetAllSubtypes<T>(Assembly assembly)
- {
- return GetAllSubtypes(typeof(T), assembly);
- }
- /// <summary>
- /// Retrieve all subclasses that inherit from the target type in a specific assembly
- /// </summary>
- /// <param name="assembly"></param>
- /// <param name="baseType"></param>
- /// <returns></returns>
- public static Type[] GetAllSubtypes(Type baseType, Assembly assembly)
- {
- #if DEBUG
- CheckBasetype(baseType);
- #endif
- return assembly.GetCustomAttributes<GeneratedDirectRetrieveAttribute>()
- .Where(a => IsBaseType(a.type, baseType))
- .Select(a => a.type)
- .Distinct()
- .ToArray()
- ;
- }
- static void CheckAttribute(Type attributeType)
- {
- if (!typeof(DirectRetrieveAttribute).IsAssignableFrom(attributeType))
- {
- throw new($"type {attributeType} is not a DirectRetrieveAttribute");
- }
- }
- // [Conditional("DIRECT_RETRIEVE_ATTRIBUTE_STRICT")]
- static void CheckBasetype(Type baseType)
- {
- if (!IsTypeRetrievable(baseType))
- {
- throw new($"type {baseType} is not retrievable, which should inherit from IDirectRetrieve");
- }
- }
- public static bool IsTypeRetrievable(Type type)
- {
- return IsBaseType(type, typeof(IDirectRetrieve));
- }
- static bool IsBaseType(Type subType, Type baseType)
- {
- if (subType == baseType)
- return false;
- if (baseType.IsInterface)
- return baseType.IsAssignableFrom(subType);
- else
- return subType.IsSubclassOf(baseType);
- }
- static T SetAttributeValue<T>(T attr, MemberInfo targetInfo) where T : DirectRetrieveAttribute
- {
- attr.targetInfo = targetInfo;
- attr.OnReceiveTarget();
- return attr;
- }
- }
- }
|