290 lines
10 KiB
C#
290 lines
10 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Reflection;
|
||
|
using Cysharp.Threading.Tasks;
|
||
|
using System.Diagnostics;
|
||
|
using System.Linq;
|
||
|
using System.Text;
|
||
|
using System.Threading;
|
||
|
using System.Threading.Tasks;
|
||
|
|
||
|
namespace BITKit
|
||
|
{
|
||
|
public class ReflectionHelper
|
||
|
{
|
||
|
public static BindingFlags Flags => BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||
|
public static InitializationState State = InitializationState.None;
|
||
|
private static Type[] types = Type.EmptyTypes;
|
||
|
private static IEnumerable<MethodInfo> methods = new List<MethodInfo>();
|
||
|
private static IEnumerable<FieldInfo> fields = new List<FieldInfo>();
|
||
|
private static readonly Dictionary<Type, MethodInfo[]> methodsCache = new();
|
||
|
private static readonly Dictionary<Type, FieldInfo[]> fieldsCache = new();
|
||
|
private static readonly Dictionary<Attribute, Attribute[]> attributes = new();
|
||
|
public static async Task<IEnumerable<MethodInfo>> GetMethods<Att>() where Att : Attribute
|
||
|
{
|
||
|
await EnsureConfig();
|
||
|
var type = typeof(Att);
|
||
|
if (methodsCache.TryGetValue(type, out var _methods))
|
||
|
{
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_methods = methods.ToArray()
|
||
|
.Where(x => x.GetCustomAttribute<Att>() is not null
|
||
|
).ToArray();
|
||
|
methodsCache.Add(type, _methods);
|
||
|
}
|
||
|
return _methods;
|
||
|
}
|
||
|
public static async Task<IEnumerable<FieldInfo>> GetFields<Att>() where Att : Attribute
|
||
|
{
|
||
|
await EnsureConfig();
|
||
|
var type = typeof(Att);
|
||
|
if (fieldsCache.TryGetValue(type, out var _fields))
|
||
|
{
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_fields = fields
|
||
|
.Where(x => x.GetCustomAttribute<Att>() is not null
|
||
|
).ToArray();
|
||
|
fieldsCache.Add(type, _fields);
|
||
|
}
|
||
|
return _fields;
|
||
|
}
|
||
|
public static async Task<IEnumerable<Type>> GetTypes()
|
||
|
{
|
||
|
await EnsureConfig();
|
||
|
return types;
|
||
|
}
|
||
|
public static async Task<IEnumerable<Type>> GetTypes<T>()
|
||
|
{
|
||
|
var type = typeof(T);
|
||
|
await EnsureConfig();
|
||
|
var currentTheadID = Thread.CurrentThread.ManagedThreadId.ToString();
|
||
|
BIT4Log.Log<ReflectionHelper>($"GetTypes运行于线程:{currentTheadID}");
|
||
|
return types
|
||
|
.Where(x => x.IsAbstract is false)
|
||
|
.Where(x => type.IsAssignableFrom(x));
|
||
|
}
|
||
|
public static async Task<IEnumerable<Att>> GetAttributes<Att>() where Att : Attribute
|
||
|
{
|
||
|
await EnsureConfig();
|
||
|
List<Att> atts = new();
|
||
|
var _atts = types
|
||
|
.Where(x => x.IsAbstract is false)
|
||
|
.Where(x => x.GetCustomAttribute<Att>() is not null)
|
||
|
.Select(x => x.GetCustomAttribute<Att>());
|
||
|
foreach (var att in _atts)
|
||
|
{
|
||
|
if (att is not null)
|
||
|
{
|
||
|
atts.Add(att);
|
||
|
}
|
||
|
}
|
||
|
return atts;
|
||
|
}
|
||
|
public static async Task<IEnumerable<T>> GetInstances<T>() where T : class
|
||
|
{
|
||
|
await EnsureConfig();
|
||
|
var results = new List<T>();
|
||
|
var instances = (await GetTypes<T>())
|
||
|
.Where(x => x.IsClass)
|
||
|
.Where(x => x.IsAbstract is false)
|
||
|
#if UNITY
|
||
|
//.Where(x=>x.IsAssignableFrom(typeof(UnityEngine.Object))is false)
|
||
|
.Where(x=>typeof(UnityEngine.Object).IsAssignableFrom(x) is false)
|
||
|
#endif
|
||
|
.Where(x => x.ContainsGenericParameters is false)
|
||
|
.Select(x =>
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
var instance = System.Activator.CreateInstance(x) as T;
|
||
|
//DI.Inject(instance);
|
||
|
return instance;
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
BIT4Log.LogException(e);
|
||
|
}
|
||
|
return null;
|
||
|
});
|
||
|
|
||
|
foreach (var instance in instances)
|
||
|
{
|
||
|
if (instance is not null)
|
||
|
{
|
||
|
results.Add(instance);
|
||
|
}
|
||
|
}
|
||
|
return results;
|
||
|
}
|
||
|
private static async Task EnsureConfig()
|
||
|
{
|
||
|
await TaskHelper.WaitUntil(() => State == InitializationState.Initialized);
|
||
|
await UniTask.SwitchToThreadPool();
|
||
|
}
|
||
|
internal static async UniTask Init()
|
||
|
{
|
||
|
if(State is InitializationState.Initializing)
|
||
|
{
|
||
|
await TaskHelper.WaitUntil(() => State is InitializationState.Initialized);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
State = InitializationState.Initializing;
|
||
|
|
||
|
await UniTask.SwitchToThreadPool();
|
||
|
|
||
|
Stopwatch stopWatch = new Stopwatch();
|
||
|
stopWatch.Start();
|
||
|
|
||
|
var loadedAssemblies = BITApp.Assemblies.IsValid()
|
||
|
? BITApp.Assemblies
|
||
|
: GetAllAssemblies();
|
||
|
BIT4Log.Log<ReflectionHelper>($"已加载程序集:{loadedAssemblies.Length}个");
|
||
|
var result = new List<Type>();
|
||
|
for (var i = 0; i < loadedAssemblies.Length; i++)
|
||
|
{
|
||
|
var asm = loadedAssemblies[i];
|
||
|
try
|
||
|
{
|
||
|
foreach (var x in asm.GetExportedTypes())
|
||
|
{
|
||
|
var rootNamespace = x.Namespace;
|
||
|
if (string.IsNullOrEmpty(rootNamespace))
|
||
|
{
|
||
|
rootNamespace = Constant.System.Internal;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rootNamespace = rootNamespace.Split(@".").First();
|
||
|
}
|
||
|
|
||
|
if (BITApp.Settings.whiteList.Count > 0)
|
||
|
{
|
||
|
if (BITApp.Settings.whiteList.Contains(rootNamespace))
|
||
|
{
|
||
|
result.Add(x);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (BITApp.Settings.blackList.Contains(rootNamespace) is false)
|
||
|
{
|
||
|
result.Add(x);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
catch
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
|
||
|
try
|
||
|
{
|
||
|
BITApp.CancellationToken.ThrowIfCancellationRequested();
|
||
|
}
|
||
|
catch (System.Exception)
|
||
|
{
|
||
|
Reload();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
var ignoreWatch = new Stopwatch();
|
||
|
var allTypesCount = result.Count;
|
||
|
ignoreWatch.Start();
|
||
|
types = result
|
||
|
.ToArray();
|
||
|
|
||
|
StringBuilder allNamespaceBuilder = new();
|
||
|
foreach (var x in types.Select(x => x.Namespace).Distinct())
|
||
|
{
|
||
|
allNamespaceBuilder.AppendLine(x);
|
||
|
}
|
||
|
|
||
|
ignoreWatch.Stop();
|
||
|
|
||
|
BIT4Log.Log<ReflectionHelper>($"已加载的命名空间:\n{allNamespaceBuilder}");
|
||
|
BIT4Log.Log<ReflectionHelper>($"忽略部分Types:{ignoreWatch.ElapsedMilliseconds}ms");
|
||
|
methods = types.SelectMany(x => x.GetMethods());
|
||
|
fields = types.SelectMany(x => x.GetFields());
|
||
|
stopWatch.Stop();
|
||
|
BIT4Log.Log<ReflectionHelper>($"获取所有Types:{stopWatch.ElapsedMilliseconds}ms");
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
BIT4Log.LogException(e);
|
||
|
}
|
||
|
|
||
|
State = InitializationState.Initialized;
|
||
|
BIT4Log.Log<ReflectionHelper>("已完成初始化");
|
||
|
}
|
||
|
|
||
|
private static Assembly[] GetAllAssemblies()
|
||
|
{
|
||
|
return AppDomain.CurrentDomain.GetAssemblies();
|
||
|
//return AppDomain.CurrentDomain.GetReferanceAssemblies().ToArray();
|
||
|
// var assemblies = new List<Assembly>();
|
||
|
// foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||
|
// {
|
||
|
// assemblies.Add(assembly);
|
||
|
// foreach (var assemblyName in assembly.GetReferencedAssemblies())
|
||
|
// {
|
||
|
// assemblies.Add(Assembly.Load(assemblyName));
|
||
|
// }
|
||
|
// }
|
||
|
// return assemblies.Distinct().ToArray();
|
||
|
}
|
||
|
|
||
|
[ExcuteOnStop]
|
||
|
public static void Reload()
|
||
|
{
|
||
|
State = InitializationState.None;
|
||
|
types = Type.EmptyTypes;
|
||
|
methods = Array.Empty<MethodInfo>();
|
||
|
fields = Array.Empty<FieldInfo>();
|
||
|
fieldsCache.Clear();
|
||
|
methodsCache.Clear();
|
||
|
}
|
||
|
}
|
||
|
public static class Extents
|
||
|
{
|
||
|
public static List<Assembly> GetReferanceAssemblies(this AppDomain domain)
|
||
|
{
|
||
|
var list = new List<Assembly>();
|
||
|
domain.GetAssemblies().ForEach(i =>
|
||
|
{
|
||
|
GetReferanceAssemblies(i, list);
|
||
|
});
|
||
|
return list;
|
||
|
}
|
||
|
static void GetReferanceAssemblies(Assembly assembly, List<Assembly> list)
|
||
|
{
|
||
|
assembly.GetReferencedAssemblies().ForEach(i =>
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
var ass = Assembly.Load(i);
|
||
|
if (!list.Contains(ass))
|
||
|
{
|
||
|
list.Add(ass);
|
||
|
GetReferanceAssemblies(ass, list);
|
||
|
}
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
// ignored
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|