diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs
index 2a9fa7e..07d753e 100644
--- a/UIShare/GlobalVariable/DeviceManager.cs
+++ b/UIShare/GlobalVariable/DeviceManager.cs
@@ -15,11 +15,12 @@ namespace UIShare.GlobalVariable
/// 设备管理器:根据 反射实例化所有启用的设备,
/// 通过 多态统一管理,避免为每种设备单独硬编码字段。
///
- public class DeviceManager
+ public class DeviceManager:IDisposable
{
private object _lockObj = new object();
public SystemConfig _systemConfig { get; set; }
private readonly GlobalInfo _globalInfo;
+ private readonly string _scopeName;
/// 按 DeviceName 索引的设备字典,便于业务层按名取实例。
public IDictionary DeviceMap { get; private set; }
@@ -32,6 +33,8 @@ namespace UIShare.GlobalVariable
{
_systemConfig = systemConfig;
_globalInfo = globalInfo;
+ // 用 SystemConfig.Title 作为作用域唯一标识,无需反查 ConfigDic
+ _scopeName = _systemConfig.Title;
InitDevices();
}
///
@@ -108,6 +111,18 @@ namespace UIShare.GlobalVariable
DeviceMap[config.DeviceName] = instance;
}
+ // 第五步:将当前作用域注册到指纹的作用域列表,用于引用计数与安全销毁
+ if (!string.IsNullOrEmpty(_scopeName))
+ {
+ var scopeList = _globalInfo.DeviceAndScopeDic.GetOrAdd(fingerprint,
+ _ => new Lazy>(() => new List())).Value;
+ lock (scopeList)
+ {
+ if (!scopeList.Contains(_scopeName))
+ scopeList.Add(_scopeName);
+ }
+ }
+
LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}] 指纹={fingerprint}");
}
catch (Exception ex)
@@ -338,6 +353,50 @@ namespace UIShare.GlobalVariable
};
return Activator.CreateInstance(type, cfg) as IBaseInterface;
}
+
+ public void Dispose()
+ {
+ if (string.IsNullOrEmpty(_scopeName)) return;
+
+ // 遍历当前作用域用到的所有指纹,逐一移除本作用域的引用
+ var fingerprintsToRemove = new List();
+
+ foreach (var kvp in _globalInfo.DeviceAndScopeDic)
+ {
+ string fingerprint = kvp.Key;
+ var scopeList = kvp.Value.IsValueCreated ? kvp.Value.Value : null;
+ if (scopeList == null) continue;
+
+ lock (scopeList)
+ {
+ scopeList.Remove(_scopeName);
+
+ // 引用归零 → 标记为待清理
+ if (scopeList.Count == 0)
+ fingerprintsToRemove.Add(fingerprint);
+ }
+ }
+
+ // 对引用归零的指纹:销毁设备实例 + 从全局池中移除
+ foreach (var fingerprint in fingerprintsToRemove)
+ {
+ // 尝试从 HardwarePool 取出并销毁
+ if (_globalInfo.HardwarePool.TryRemove(fingerprint, out var lazy))
+ {
+ if (lazy.IsValueCreated && lazy.Value is IBaseInterface device)
+ {
+ try { device.Close(); }
+ catch { /* 销毁时忽略异常 */ }
+ LoggerHelper.Info($"指纹 [{fingerprint}] 无作用域引用,已销毁设备实例。");
+ }
+ }
+
+ // 同步清除 DeviceAndScopeDic 中的空条目
+ _globalInfo.DeviceAndScopeDic.TryRemove(fingerprint, out _);
+ }
+
+ DeviceMap.Clear();
+ }
#endregion
}
}
diff --git a/UIShare/GlobalVariable/GlobalInfo.cs b/UIShare/GlobalVariable/GlobalInfo.cs
index fde936c..2e7f0f1 100644
--- a/UIShare/GlobalVariable/GlobalInfo.cs
+++ b/UIShare/GlobalVariable/GlobalInfo.cs
@@ -19,6 +19,9 @@ namespace UIShare.GlobalVariable
/// 硬件指纹 → 设备实例的并发池,确保同一物理硬件全局只创建一个驱动实例。
public ConcurrentDictionary> HardwarePool { get; set; }
+ /// 硬件指纹 → 正在使用该设备的作用域名称列表,用于引用计数与安全销毁。
+ public ConcurrentDictionary>> DeviceAndScopeDic { get; set; }
+
public String UserName { get; set; } = "Not Logged in";
public bool IsAdmin { get; set; } = true;
public string CurrentOpeningScope;
@@ -42,6 +45,7 @@ namespace UIShare.GlobalVariable
ConfigDic = new();
ScopeDic = new();
HardwarePool = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase);
+ DeviceAndScopeDic = new ConcurrentDictionary>>(StringComparer.OrdinalIgnoreCase);
CurrentScope = "default";
}