using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace TeamAAS.Modularity { /// /// 通用程序集/模块扫描器:引擎、相机、机器人、通讯、供料器、插件等模块的 /// 类型发现统一走这里(原先每个 Manager 各写一套 AppDomain 反射)。 /// /// - 扫描范围:AppDomain 已加载的全部程序集(主程序直接引用的 + PluginLoader /// 从 Runtime\Plugins 动态加载的插件 DLL;插件加载先于各模块的 Discover); /// - 类型解析容错:程序集部分类型加载失败(依赖缺失)时保留其余可用类型; /// - 结果缓存:按接口类型缓存,程序集数量变化(新插件加载)自动重扫。 /// public static class AssemblyScanner { private static readonly object _sync = new object(); /// 类型缓存:接口类型 → 实现类型列表 private static readonly Dictionary> _cache = new Dictionary>(); /// 程序集数量指纹(变化 = 有新程序集加载,缓存失效) private static int _assemblyStamp = -1; /// 枚举 AppDomain 全部程序集 public static IEnumerable GetAllAssemblies() => AppDomain.CurrentDomain.GetAssemblies(); /// 枚举全部具体类型(容错:ReflectionTypeLoadException 时保留可用类型) public static IEnumerable GetAllTypes() { foreach (var asm in GetAllAssemblies()) { Type[] types; try { types = asm.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types?.Where(t => t != null).ToArray() ?? Type.EmptyTypes; } catch { continue; } foreach (var t in types) if (t != null) yield return t; } } /// /// 查找实现 TInterface 的全部具体类型(非抽象/非接口/非泛型定义;带缓存)。 /// 插件 DLL 由 PluginLoader 在启动时加载进 AppDomain,新插件加载后缓存自动失效重扫。 /// public static IReadOnlyList FindImplementations() where T : class { lock (_sync) { var stamp = GetAllAssemblies().Count(); if (_assemblyStamp != stamp || !_cache.TryGetValue(typeof(T), out var list)) { list = GetAllTypes() .Where(t => !t.IsAbstract && !t.IsInterface && !t.IsGenericTypeDefinition && typeof(T).IsAssignableFrom(t)) .Distinct() .ToList(); _cache[typeof(T)] = list; _assemblyStamp = stamp; } return list; } } /// /// 创建 TInterface 的全部实例(无参构造,构造失败跳过并记日志)。 /// 业务键去重(如 EngineName)由调用方负责。 /// public static IReadOnlyList CreateInstances() where T : class { var result = new List(); foreach (var type in FindImplementations()) { try { if (Activator.CreateInstance(type) is T instance) result.Add(instance); } catch (Exception ex) { // 构造失败(SDK 运行库缺失等)→ 跳过该实现; // 记日志便于诊断"引擎没起来/主页画面空白"这类静默降级问题 try { AppLogger.Warning($"模块 {type.FullName} 实例化失败,已跳过: {ex.Message}", "模块扫描"); } catch { } } } return result; } /// 清空缓存(强制下次重扫;一般无需调用) public static void InvalidateCache() { lock (_sync) { _cache.Clear(); _assemblyStamp = -1; } } } }