using Common.Attributes; using DeviceCommand.Base; using Model.Models; using Prism.Events; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading; using UIShare.PubEvent; namespace UIShare.GlobalVariable { /// /// 硬件数据广播器(中间层,全局单例): /// 直接基于 GlobalInfo.HardwarePool 中的设备指纹字典进行统一采样, /// 每个物理设备只采样一次,然后向所有引用该设备的作用域分别广播 HardwareDataReportedEvent。 /// 解决多作用域共享同一物理设备时的重复采样问题。 /// DeviceCommand 层无需引用 Prism,完全解耦。 /// public class HardwareDataBroadcaster : IDisposable { private readonly IEventAggregator _eventAggregator; private readonly GlobalInfo _globalInfo; /// 采样定时器 private readonly DispatcherTimer _sampleTimer; /// /// 已注册的采样项:(Fingerprint, MethodName, 编译后的委托, DeviceInstance) /// 委托签名统一为 Func<object, CancellationToken, Task<string>> /// - 第一个参数 = 设备实例(open delegate 风格,编译时已做类型转换) /// - 第二个参数 = CancellationToken(无参方法会忽略它) /// - 返回值 = Task<string> /// private readonly List<(string Fingerprint, string MethodName, Func> Invoker, object Device)> _registeredMethods = new(); private CancellationTokenSource? _cts; private bool _disposed; /// 采样间隔(默认 1000ms) public TimeSpan SampleInterval { get => _sampleTimer.Interval; set => _sampleTimer.Interval = value; } public HardwareDataBroadcaster(GlobalInfo globalInfo, IEventAggregator eventAggregator) { _globalInfo = globalInfo; _eventAggregator = eventAggregator; _sampleTimer = new DispatcherTimer(DispatcherPriority.Normal) { Interval = TimeSpan.FromMilliseconds(1000) }; _sampleTimer.Tick += OnSampleTick; } /// /// 将 MethodInfo 编译为强类型委托,后续调用零反射开销。 /// 统一签名为 Func<object, CancellationToken, Task<string>>: /// - 无参方法:忽略 CancellationToken /// - 带 CancellationToken 方法:直接透传 /// private static Func> BuildInvoker(MethodInfo method) { var deviceParam = Expression.Parameter(typeof(object), "device"); var ctParam = Expression.Parameter(typeof(CancellationToken), "ct"); // 将 object 转型为方法的声明类型 var castDevice = Expression.Convert(deviceParam, method.DeclaringType!); // 根据方法签名决定传参 var parms = method.GetParameters(); Expression[] callArgs = parms.Length == 1 ? new Expression[] { ctParam } : Array.Empty(); var call = Expression.Call(castDevice, method, callArgs); return Expression.Lambda>>( call, deviceParam, ctParam).Compile(); } /// /// 扫描 GlobalInfo.HardwarePool 中所有已创建的物理设备, /// 反查可监测方法并编译为委托。每个指纹只注册一次,反射只执行一次。 /// public void Discover() { _registeredMethods.Clear(); foreach (var poolEntry in _globalInfo.HardwarePool) { string fingerprint = poolEntry.Key; var lazy = poolEntry.Value; // 只监控已经实例化的设备 if (!lazy.IsValueCreated || lazy.Value == null) continue; var device = lazy.Value; var deviceType = device.GetType(); var methods = deviceType.GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(m => { if (m.GetCustomAttribute() == null) return false; if (m.ReturnType != typeof(Task)) return false; var parms = m.GetParameters(); return parms.Length == 0 || (parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken)); }); foreach (var method in methods) { var invoker = BuildInvoker(method); _registeredMethods.Add((fingerprint, method.Name, invoker, device)); } } } /// 获取指定硬件指纹当前被哪些作用域引用 private List GetScopesForFingerprint(string fingerprint) { if (_globalInfo.DeviceAndScopeDic.TryGetValue(fingerprint, out var lazy)) { var scopeList = lazy.Value; lock (scopeList) return scopeList.ToList(); } return new List(); } /// 启动采样广播(幂等) public void Start() { if (_disposed) return; _cts ??= new CancellationTokenSource(); if (!_sampleTimer.IsEnabled) _sampleTimer.Start(); } /// 停止采样 public void Stop() { _sampleTimer.Stop(); } private void OnSampleTick(object? sender, EventArgs e) { if (_registeredMethods.Count == 0 || _disposed) return; var token = _cts?.Token ?? CancellationToken.None; var now = DateTime.Now; foreach (var entry in _registeredMethods) { // fire-and-forget:每个通道独立采样,完成后自行广播 _ = Task.Run(async () => { try { // 直接委托调用,零反射开销 string raw = await entry.Invoker(entry.Device, token).ConfigureAwait(false); if (!double.TryParse(raw, out double value)) return; // 向所有引用该物理设备的作用域分别广播 var scopes = GetScopesForFingerprint(entry.Fingerprint); foreach (var scope in scopes) { _eventAggregator.GetEvent().Publish(new HardwareReportArgs { Scope = scope, HardwareFingerprint = entry.Fingerprint, MethodName = entry.MethodName, Value = value, Time = now }); // 同步检查该作用域 ValueLimitList 是否超限 string MonitorSatus= ValueLimitAlarmHelper.CheckAlarm(scope, entry.Fingerprint, entry.MethodName, value, _globalInfo); if (MonitorSatus != "" || MonitorSatus != "未报警") { // _eventAggregator.GetEvent().Publish(entry.Fingerprint, MonitorSatus); } } } catch { // 单个通道故障不干扰其他通道 } }, token); } // 不在 UI 线程 await——任务在线程池上自行完成并广播事件, // DispatcherTimer 按设定间隔准时触发下一次 Tick。 } public void Dispose() { if (_disposed) return; _disposed = true; _sampleTimer.Stop(); _sampleTimer.Tick -= OnSampleTick; try { _cts?.Cancel(); } catch { } _cts?.Dispose(); _cts = null; _registeredMethods.Clear(); } } }