修复监控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 =>
{
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();
return parms.Length == 0 ||
(parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken));
+3 -1
View File
@@ -233,7 +233,9 @@ namespace MonitorModule.ViewModels
.Where(m =>
{
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();
return parms.Length == 0 ||
(parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken));
@@ -33,12 +33,12 @@ namespace UIShare.GlobalVariable
/// <summary>
/// 已注册的采样项:(Fingerprint, MethodName, 编译后的委托, DeviceInstance)
/// 委托签名统一为 Func&lt;object, CancellationToken, Task&lt;string&gt;&gt;
/// 委托签名统一为 Func&lt;object, CancellationToken, Task&lt;double&gt;&gt;
/// - 第一个参数 = 设备实例(open delegate 风格,编译时已做类型转换)
/// - 第二个参数 = CancellationToken(无参方法会忽略它)
/// - 返回值 = Task&lt;string&gt;
/// - 返回值 = Task&lt;double&gt;Task&lt;string&gt; 方法自动 TryParse 为 double
/// </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 bool _disposed;
@@ -76,11 +76,13 @@ namespace UIShare.GlobalVariable
/// <summary>
/// 将 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 方法:直接透传
/// </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 ctParam = Expression.Parameter(typeof(CancellationToken), "ct");
@@ -96,8 +98,24 @@ namespace UIShare.GlobalVariable
var call = Expression.Call(castDevice, method, callArgs);
return Expression.Lambda<Func<object, CancellationToken, Task<string>>>(
call, deviceParam, ctParam).Compile();
if (method.ReturnType == typeof(Task<double>))
{
// Task<double> 方法:直接返回
return Expression.Lambda<Func<object, CancellationToken, Task<double>>>(
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>
@@ -126,7 +144,9 @@ namespace UIShare.GlobalVariable
.Where(m =>
{
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();
return parms.Length == 0 ||
(parms.Length == 1 && parms[0].ParameterType == typeof(CancellationToken));
@@ -184,10 +204,10 @@ namespace UIShare.GlobalVariable
{
try
{
// 直接委托调用,零反射开销
string raw = await entry.Invoker(entry.Device, token).ConfigureAwait(false);
// 直接委托调用,零反射开销Task<double> 路径)或自动 TryParseTask<string> 路径)
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 _);