.NET Framework 4.8 的通用工具库。解决方案里的主工程输出类型是 WinExe,但 Program.Main 目前是空壳,
实际是当类库用的:Modbus 从站/主站、跨平台高精度定时器、多媒体时钟、数字滤波与曲线拟合、异步日志、
FTP 与 Windows Shell 文件操作、DataGridView 增强、CPU 拓扑与线程亲和性,以及字节/时间/IP 等基础转换。
| 项目 | 说明 |
|---|---|
UniversalUtilities |
主工程(.NET Framework 4.8,C# 12)。Debug 为 x86(含 unsafe 指针代码),Release 为 AnyCPU |
UniversalUtilities.Tests |
MSTest 3.11.1 测试工程(必须同为 x86,否则运行期 BadImageFormatException) |
| 路径 | 说明 |
|---|---|
UniversalUtilities\ModbusServer.cs |
Modbus 从站(服务端),基于 NModbus 3.0.83;TCP / UDP / RTU,保留原有对外 API 与地址语义 |
UniversalUtilities\ModbusClient_TCP.cs |
Modbus 主站(客户端),基于 NModbus;只读保持寄存器,float 字节序与旧实现逐字节一致 |
UniversalUtilities\CrossPlatformTimer.cs |
跨平台高精度定时器:Windows 用可等待定时器 + 自适应 busy-spin,Linux 用 timerfd/eventfd |
UniversalUtilities\HighResTimer.cs |
Windows 专用高精度定时器(MMCSS "Pro Audio" + 可选线程亲和性绑定) |
UniversalUtilities\MMTimer.cs |
winmm 多媒体时钟(timeSetEvent/timeKillEvent),带同步对象封送与优雅停止 |
UniversalUtilities\Filters.cs |
均值 / 中位数 / 奥林匹克 / 高保真中位数滤波(滑动有序窗口,O(N)) |
UniversalUtilities\GaussianFilter.cs |
高斯滤波(偶数核自动取奇数,避免半样本偏移) |
UniversalUtilities\SavitzkyGolayFilter.cs |
Savitzky-Golay 平滑(最小二乘卷积系数) |
UniversalUtilities\Fitting.cs |
最小二乘多项式拟合(法方程 + 列主元高斯消元) |
UniversalUtilities\ArrayManipulator.cs |
数组统计:最值、均值、绝对均值、峰峰值、半峰值(含 unsafe 指针重载) |
UniversalUtilities\Logger.cs |
异步日志:入队即返回,后台线程落盘,按日期分片、单文件 8 MB 轮转 |
UniversalUtilities\FTPClient.cs |
FluentFTP 封装(连接、列目录、上传下载) |
UniversalUtilities\FileOperateProxy.cs |
Windows Shell(SHFileOperation)文件操作:删除到回收站、移动、复制、重名自动改名 |
UniversalUtilities\CustomDataGridView.cs、ColumnStruct.cs |
DataGridView 增强:列显示/列宽持久化、字号缩放、行高调整、滚动与拖拽 |
UniversalUtilities\CpuTopology.cs |
CPU Set / P 核 E 核查询、逻辑处理器索引映射、把线程绑定到指定 CPU |
UniversalUtilities\NativeMethods.cs |
Win32 P/Invoke:内存拷贝、winmm 定时器、comctl32 图像列表拖拽 |
UniversalUtilities\Utilities.cs |
通用工具:内存拷贝、字节序与十六进制/BCD、CRC16、时间戳与 OLE 自动化日期互转、IP↔整数、枚举显示名、压缩解压等 |
UniversalUtilities\Exceptions.cs |
Modbus 相关异常类型(连接、CRC、功能码、数量、起始地址等) |
UniversalUtilities\Program.cs |
程序入口(当前为空壳,Application.Run 被注释) |
UniversalUtilities\Properties\ |
程序集信息与资源(*.Designer.cs 为自动生成,不要手工改) |
UniversalUtilities.Tests\ |
测试工程、测试用例与一键运行脚本(见 UniversalUtilities.Tests\README.md) |
docs\ |
代码审查报告(历史缺陷与修复记录)、测试覆盖率报告 |
通过 packages.config 还原到仓库内的 packages\ 目录(旧的 NuGet 方式,不生成 PackageReference):
FluentFTP 55.0.0、NModbus 3.0.83、MathNet.Numerics 5.0.0、Newtonsoft.Json 13.0.4、 System.Memory 4.6.3、System.Buffers 4.6.1、System.Numerics.Vectors 4.6.1、 System.Runtime.CompilerServices.Unsafe 6.1.2、System.IO.Compression.ZipFile 4.3.0;测试用 MSTest 3.11.1。
- Modbus 地址映射:Modbus 地址 A 对应
localArray[A + 1],四个数据容器(保持寄存器/输入寄存器/线圈/离散输入) 的下标 0 一律保留不用。 - 单元标识:unit id 等于
UnitIdentifier,或 unit id = 0(广播寻址)时才响应,其它请求直接丢弃(不返回异常)。 - 功能码开关:
FunctionCodeXxxDisabled = true时,对应功能码请求返回异常响应(异常码 1:非法功能)。 - 浮点寄存器:
SetHoldingRegisterValue(address, value)把 float 的高 16 位写到localArray[address]、 低 16 位写到localArray[address + 1];主站读回的 float 与该布局逐字节一致。 - 日志落盘:
{程序目录}\logs\{前缀}_{yyyyMMdd}({编号}).log,UTF-8(无 BOM),单文件超过 8 MB 自动切下一个编号。 队列上限 100000;队列满或已经停止接收时,日志被静默丢弃并计入Log.DroppedCount,写入方法不抛异常、不阻塞业务线程。 - 定时器回调:
InvokeHandlersOnThreadPool默认为false,即在定时器线程上同步回调(回调耗时会长会拖慢后续周期); 自旋窗口会按实测漂移自适应调整,CPUAffinity打开时把定时线程绑到前两个逻辑 CPU。 - 文件操作返回值:
FileOperateProxy的删除/移动/复制返回0表示成功,其它非零值是 Shell 错误码,-200表示托管异常(异常消息写入errorMsg)。
// Modbus 从站:监听 505 端口,数据容器索引 0 保留(索引 1 对应 Modbus 地址 0)
using (var server = new ModbusServer { Port = 505, UnitIdentifier = 1 })
{
server.holdingRegisters[1] = 1234; // 写保持寄存器
short value = server.holdingRegisters[1];
server.SetHoldingRegisterValue(10, 3.14f); // float 拆成两个寄存器
server.HoldingRegistersChanged += (register, count) => { /* 主站写入后的处理 */ };
server.Listen(); // TCP(UDPFlag / SerialFlag 可切换到 UDP / RTU)
// ... 运行中 ...
server.StopListening();
}
// Modbus 主站:读保持寄存器(只支持 FC3)
using (var client = new ModbusClient_TCP("127.0.0.1", 505, demo: false))
{
client.Connect();
float[] values = client.ReadHoldingRegisters(startingAddress: 0, quantity: 10);
client.Disconnect();
}
// 异步日志:入队即返回,后台线程落盘到 {程序目录}\logs\{前缀}_{日期}({编号}).log
Log.WriteLog("设备已连接", source: "Main", preText: "app");
Log.WriteUnifiedLog("标定完成", category: "校准", source: "Calib");
Log.Flush(); // 退出前确保落盘(或 ShutdownAndFlush)
// 滤波与拟合
double[] smooth = Filters.MeanFilter(data, 5);
double[] gauss = GaussianFilter.Gaussian(data, stdDev: 2.0, kernelSize: 5);
double[] coefficients = Fitting.GetCoefficient(xs, ys, xs.Length, dimension: 2); // 按升幂排列
var sg = new SavitzkyGolayFilter(sidePoints: 5, polynomialOrder: 2); // 构造时算好系数,实例可复用
double[] filtered = sg.Process(data);
// 高精度周期定时器(回调默认在定时器线程上同步执行)
using (var timer = new CrossPlatformTimer(intervalMs: 10, spinWindowMs: 2))
{
timer.InvokeHandlersOnThreadPool = true; // 回调耗时较长时建议打开
timer.Elapsed += (s, e) => { /* 周期任务 */ };
timer.Start();
// ...
timer.Stop();
}推荐用 Visual Studio 打开 UniversalUtilities.sln 直接生成;命令行方式(在 VS 开发者命令提示符里 msbuild 即在 PATH 上):
# 编译整个解决方案
msbuild UniversalUtilities.sln /p:Configuration=Debug /t:Rebuild /v:m /nologo
# 只编译主工程,并顺带生成 XML 文档(工程默认不生成文档文件)
msbuild UniversalUtilities\UniversalUtilities.csproj /p:Configuration=Debug /p:DocumentationFile=bin\Debug\UniversalUtilities.xml注意:
/p:DocumentationFile请只对主工程使用。若在解决方案级别传入,测试工程也会跟着生成文档, 而测试用例的公开成员没有文档注释,会刷出一批 CS1591 警告。
# 一键:编译 → 跑全部用例 → 采集并汇总覆盖率(Debug,默认)
powershell -ExecutionPolicy Bypass -File UniversalUtilities.Tests\RunTests.ps1
# Release 配置 / 列出未覆盖行 / 跳过编译
powershell -ExecutionPolicy Bypass -File UniversalUtilities.Tests\RunTests.ps1 -Configuration Release -ListUncovered
# 只跑某一类(脚本内部用命名互斥体串行化 MSBuild,适合多人同时改代码)
pwsh -NoProfile -File UniversalUtilities.Tests\RunOne.ps1 -Filter 'FullyQualifiedName~ModbusTests'当前基线(2026-09-24 实测,Debug):242 个用例全部通过,行覆盖率 86.7%(3823/4407)、
分支点覆盖率 93.5%(550/588)。未覆盖部分主要是 Linux-only 分支、真实串口/公网 FTP、以及需要极端并发才能触发的防御代码,
逐条原因见 docs\UniversalUtilities-测试覆盖率报告.md。
- 公共可见的类型与成员都有中文 XML 文档注释(
<summary>/<param>/<returns>/<exception>), 编译时CS1591(缺少文档注释)保持为 0;提交前请勿引入新的文档告警。 - 文档注释里出现
<、>、&必须转义为<、>、&;结束标签不要写错(例如</summary>)。 - 字段名不加下划线前缀(
private readonly object syncRoot;这种形式);唯一例外是 C# 保留字, 锁对象字段写作@lock。 - 成员级说明用
///,行内说明用//;Properties\*.Designer.cs、AssemblyInfo.cs由工具生成,不要手工加注释。 - 已知遗留告警:16 条
CS8632(CrossPlatformTimer.cs/HighResTimer.cs在未开启#nullable的上下文里使用?可空注解), 属历史代码,未做改动。
| 文档 | 内容 |
|---|---|
docs\UniversalUtilities-代码审查报告.md |
历史缺陷清单与修复记录(含旧手写 Modbus 实现的问题:FC5/FC6 地址越界、FC15/FC16 字段不匹配、定时器句柄泄漏等) |
docs\UniversalUtilities-测试覆盖率报告.md |
覆盖率明细、未覆盖行号与原因 |
UniversalUtilities.Tests\README.md |
测试工程的使用说明、测试文件一览与约定 |