VisualEngineManager.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. namespace TeamAAS.Vision
  6. {
  7. /// <summary>
  8. /// 视觉引擎管理器(懒汉单例,Lazy 线程安全)。
  9. ///
  10. /// 职责:
  11. /// 1. 引擎探测(Discover):通过通用模块扫描器(AssemblyScanner)收集
  12. /// IVisualEngine 实现——插件 DLL 由 PluginLoader 在启动时加载进 AppDomain
  13. /// (Runtime\Plugins 目录),无需硬编码已知引擎程序集列表;
  14. /// 2. 引擎切换(SetCurrent):按配置的 EngineName 一键切换;
  15. /// 3. 引擎取用(GetOrLoad):按名称取引擎,找不到回退第一个。
  16. ///
  17. /// 引擎实现位于各引擎插件类库(如 Plugins.Vpp),本管理器只依赖抽象接口,
  18. /// 引擎 SDK 的加载与解析由插件体系完成 —— 引擎可整体替换,宿主零改动。
  19. /// </summary>
  20. public sealed class VisualEngineManager
  21. {
  22. /// <summary>懒汉单例:首次访问 Instance 时才创建(Lazy 默认 ExecutionAndPublication 线程安全)</summary>
  23. private static readonly Lazy<VisualEngineManager> _lazy =
  24. new Lazy<VisualEngineManager>(() => new VisualEngineManager(), LazyThreadSafetyMode.ExecutionAndPublication);
  25. /// <summary>全局单例入口</summary>
  26. public static VisualEngineManager Instance => _lazy.Value;
  27. private readonly List<IVisualEngine> _engines = new List<IVisualEngine>();
  28. private bool _discovered;
  29. private VisualEngineManager() { }
  30. /// <summary>
  31. /// 反射创建 AppDomain 内全部 IVisualEngine 实现实例(无参构造;构造失败跳过)。
  32. /// 自包含实现,不依赖外部扫描器(原 Global 的 AssemblyScanner)——引擎插件 DLL
  33. /// 由 PluginLoader 在启动时先行加载进 AppDomain,故此处直接扫描已加载程序集即可。
  34. /// </summary>
  35. private static IEnumerable<IVisualEngine> CreateEngineInstances()
  36. {
  37. foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
  38. {
  39. Type[] types;
  40. try { types = asm.GetTypes(); }
  41. catch (System.Reflection.ReflectionTypeLoadException ex)
  42. {
  43. types = ex.Types?.Where(t => t != null).ToArray() ?? Type.EmptyTypes;
  44. }
  45. catch { continue; }
  46. foreach (var t in types)
  47. {
  48. if (t == null || t.IsAbstract || t.IsInterface || t.IsGenericTypeDefinition) continue;
  49. if (!typeof(IVisualEngine).IsAssignableFrom(t)) continue;
  50. IVisualEngine inst;
  51. try { inst = Activator.CreateInstance(t) as IVisualEngine; }
  52. catch (Exception ex)
  53. {
  54. // 引擎 SDK 运行库缺失等 → 跳过该实现;Debug 输出便于诊断“引擎没起来/主页画面空白”
  55. System.Diagnostics.Debug.WriteLine($"[VisualEngine] 引擎 {t.FullName} 实例化失败,已跳过: {ex.Message}");
  56. continue;
  57. }
  58. if (inst != null) yield return inst;
  59. }
  60. }
  61. }
  62. /// <summary>探测到的全部可用引擎</summary>
  63. public IReadOnlyList<IVisualEngine> Engines => _engines;
  64. /// <summary>当前生效引擎(配置里的 EngineName;未配置/未找到时为第一个)</summary>
  65. public IVisualEngine Current { get; private set; }
  66. /// <summary>引擎是否已探测完成(避免宿主过早取用)</summary>
  67. public bool Discovered => _discovered;
  68. /// <summary>引擎清单变化通知</summary>
  69. public event Action EnginesChanged;
  70. /// <summary>执行探测(幂等,可重复调用)</summary>
  71. public void Discover()
  72. {
  73. if (_discovered) return;
  74. _discovered = true;
  75. // 通用模块扫描:收集全部 IVisualEngine 实现(EngineName 去重由本管理器负责)
  76. foreach (var engine in CreateEngineInstances())
  77. {
  78. if (_engines.Any(e => e.EngineName == engine.EngineName)) continue;
  79. _engines.Add(engine);
  80. }
  81. EnginesChanged?.Invoke();
  82. }
  83. /// <summary>按名称取引擎;找不到时回退第一个,完全没有引擎返回 null。</summary>
  84. public IVisualEngine GetOrLoad(string engineName)
  85. {
  86. if (_engines.Count == 0) return null;
  87. var match = _engines.FirstOrDefault(e =>
  88. string.Equals(e.EngineName, engineName, StringComparison.OrdinalIgnoreCase));
  89. return match ?? _engines[0];
  90. }
  91. /// <summary>切换当前引擎(一键切换);名称不存在返回 false。</summary>
  92. public bool SetCurrent(string engineName)
  93. {
  94. var engine = _engines.FirstOrDefault(e =>
  95. string.Equals(e.EngineName, engineName, StringComparison.OrdinalIgnoreCase));
  96. if (engine == null) return false;
  97. Current = engine;
  98. return true;
  99. }
  100. }
  101. }