修复监控bug

This commit is contained in:
2026-09-16 09:01:27 +08:00
parent 432ed2a70c
commit 96680fd4c6
3 changed files with 37 additions and 13 deletions
+3 -1
View File
@@ -433,7 +433,9 @@ namespace MonitorModule.ViewModels
.Where(m => .Where(m =>
{ {
if (m.GetCustomAttribute<MonitorableAttribute>() == null) return false; if (m.GetCustomAttribute<MonitorableAttribute>() == null) return false;
if (m.ReturnType != typeof(Task<string>)) return false; // 同时支持 Task<string> 和 Task<double> 返回类型
var rt = m.ReturnType;
if (rt != typeof(Task<string>) && rt != typeof(Task<double>)) return false;
var parms = m.GetParameters(); var parms = m.GetParameters();
return parms.Length == 0 || return parms.Length == 0 ||
(parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken)); (parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken));
+3 -1
View File
@@ -233,7 +233,9 @@ namespace MonitorModule.ViewModels
.Where(m => .Where(m =>
{ {
if (m.GetCustomAttribute<MonitorableAttribute>() == null) return false; if (m.GetCustomAttribute<MonitorableAttribute>() == null) return false;
if (m.ReturnType != typeof(Task<string>)) return false; // 同时支持 Task<string> 和 Task<double> 返回类型
var rt = m.ReturnType;
if (rt != typeof(Task<string>) && rt != typeof(Task<double>)) return false;
var parms = m.GetParameters(); var parms = m.GetParameters();
return parms.Length == 0 || return parms.Length == 0 ||
(parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken)); (parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken));
@@ -33,12 +33,12 @@ namespace UIShare.GlobalVariable
/// <summary> /// <summary>
/// 已注册的采样项:(Fingerprint, MethodName, 编译后的委托, DeviceInstance) /// 已注册的采样项:(Fingerprint, MethodName, 编译后的委托, DeviceInstance)
/// 委托签名统一为 Func&lt;object, CancellationToken, Task&lt;string&gt;&gt; /// 委托签名统一为 Func&lt;object, CancellationToken, Task&lt;double&gt;&gt;
/// - 第一个参数 = 设备实例(open delegate 风格,编译时已做类型转换) /// - 第一个参数 = 设备实例(open delegate 风格,编译时已做类型转换)
/// - 第二个参数 = CancellationToken(无参方法会忽略它) /// - 第二个参数 = CancellationToken(无参方法会忽略它)
/// - 返回值 = Task&lt;string&gt; /// - 返回值 = Task&lt;double&gt;Task&lt;string&gt; 方法自动 TryParse 为 double
/// </summary> /// </summary>
private readonly List<(string Fingerprint, string MethodName, Func<object, CancellationToken, Task<string>> Invoker, object Device)> _registeredMethods = new(); private readonly List<(string Fingerprint, string MethodName, Func<object, CancellationToken, Task<double>> Invoker, object Device)> _registeredMethods = new();
private CancellationTokenSource? _cts; private CancellationTokenSource? _cts;
private bool _disposed; private bool _disposed;
@@ -76,11 +76,13 @@ namespace UIShare.GlobalVariable
/// <summary> /// <summary>
/// 将 MethodInfo 编译为强类型委托,后续调用零反射开销。 /// 将 MethodInfo 编译为强类型委托,后续调用零反射开销。
/// 统一签名为 Func&lt;object, CancellationToken, Task&lt;string&gt;&gt; /// 统一签名为 Func&lt;object, CancellationToken, Task&lt;double&gt;&gt;
/// - Task&lt;double&gt; 方法:直接返回 double 值
/// - Task&lt;string&gt; 方法:自动 TryParse 为 double
/// - 无参方法:忽略 CancellationToken /// - 无参方法:忽略 CancellationToken
/// - 带 CancellationToken 方法:直接透传 /// - 带 CancellationToken 方法:直接透传
/// </summary> /// </summary>
private static Func<object, CancellationToken, Task<string>> BuildInvoker(MethodInfo method) private static Func<object, CancellationToken, Task<double>> BuildInvoker(MethodInfo method)
{ {
var deviceParam = Expression.Parameter(typeof(object), "device"); var deviceParam = Expression.Parameter(typeof(object), "device");
var ctParam = Expression.Parameter(typeof(CancellationToken), "ct"); var ctParam = Expression.Parameter(typeof(CancellationToken), "ct");
@@ -96,9 +98,25 @@ namespace UIShare.GlobalVariable
var call = Expression.Call(castDevice, method, callArgs); var call = Expression.Call(castDevice, method, callArgs);
return Expression.Lambda<Func<object, CancellationToken, Task<string>>>( if (method.ReturnType == typeof(Task<double>))
{
// Task<double> 方法:直接返回
return Expression.Lambda<Func<object, CancellationToken, Task<double>>>(
call, deviceParam, ctParam).Compile(); call, deviceParam, ctParam).Compile();
} }
else
{
// Task<string> 方法:await 后 TryParse 为 double
return async (device, ct) =>
{
// 通过 MethodInfo.Invoke 调用(仅 Task<string> 路径,性能可接受)
var task = (Task<string>)method.Invoke(device,
parms.Length == 1 ? new object[] { ct } : Array.Empty<object>())!;
string raw = await task.ConfigureAwait(false);
return double.TryParse(raw, out double v) ? v : double.NaN;
};
}
}
/// <summary> /// <summary>
/// 扫描 GlobalInfo.HardwarePool 中所有已创建的物理设备, /// 扫描 GlobalInfo.HardwarePool 中所有已创建的物理设备,
@@ -126,7 +144,9 @@ namespace UIShare.GlobalVariable
.Where(m => .Where(m =>
{ {
if (m.GetCustomAttribute<MonitorableAttribute>() == null) return false; if (m.GetCustomAttribute<MonitorableAttribute>() == null) return false;
if (m.ReturnType != typeof(Task<string>)) return false; // 同时支持 Task<string> 和 Task<double> 返回类型
var rt = m.ReturnType;
if (rt != typeof(Task<string>) && rt != typeof(Task<double>)) return false;
var parms = m.GetParameters(); var parms = m.GetParameters();
return parms.Length == 0 || return parms.Length == 0 ||
(parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken)); (parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken));
@@ -184,10 +204,10 @@ namespace UIShare.GlobalVariable
{ {
try try
{ {
// 直接委托调用,零反射开销 // 直接委托调用,零反射开销Task<double> 路径)或自动 TryParseTask<string> 路径)
string raw = await entry.Invoker(entry.Device, token).ConfigureAwait(false); double value = await entry.Invoker(entry.Device, token).ConfigureAwait(false);
if (!double.TryParse(raw, out double value)) return; if (double.IsNaN(value)) return;
// 采样成功,重置失败计数 // 采样成功,重置失败计数
_failureCounts.TryRemove(channelKey, out _); _failureCounts.TryRemove(channelKey, out _);