|
|
@@ -1,88 +1,58 @@
|
|
|
-# MeloongCore 项目架构
|
|
|
-
|
|
|
-[返回 MeloongCore 仓库指示](../仓库指示.md)
|
|
|
-
|
|
|
-## 1. 项目定位
|
|
|
-
|
|
|
-`MeloongCore/Shared/MeloongCore.csproj` 是通用 C# 基础库,目标框架为 .NET Standard 2.0,使用 C# 13、Nullable、Implicit Usings 和 PolySharp。
|
|
|
-
|
|
|
-它属于独立 Git 仓库,不应依赖具体上层应用或 WPF。其目标是为 Windows、macOS 及不同上层应用提供一致的基础能力。
|
|
|
-
|
|
|
-## 2. 目录结构
|
|
|
-
|
|
|
-```text
|
|
|
-MeloongCore/Shared/
|
|
|
-├─ Main.cs # 库初始化与应用名
|
|
|
-├─ Extensions/ # 集合、字符串、异常、任务和网络扩展
|
|
|
-├─ General/
|
|
|
-│ ├─ Config.cs # JSON 配置抽象
|
|
|
-│ ├─ Logger.cs # 日志抽象
|
|
|
-│ ├─ Progress.cs # 进度模型
|
|
|
-│ ├─ Worker/ # 限流与可重做 Worker
|
|
|
-│ └─ 其他通用数据结构
|
|
|
-└─ Utils/ # 文件、目录、路径、任务、网络、加密等工具
|
|
|
-```
|
|
|
-
|
|
|
-## 3. 主要能力
|
|
|
-
|
|
|
-### 3.1 文件与路径
|
|
|
-
|
|
|
-`FileUtils`、`DirectoryUtils` 和 `PathUtils` 封装文件读写、压缩包、目录遍历、路径标准化和父子关系判断,供不同上层应用复用。
|
|
|
-
|
|
|
-### 3.2 异步与 Worker
|
|
|
-
|
|
|
-- `TaskUtils` 提供程序执行、并发遍历、聚合等待等通用任务能力;
|
|
|
-- `ProgressProvider` 支持切分与聚合子进度;
|
|
|
-- `RateLimitedWorker` 合并或限制高频调用;
|
|
|
-- `RedoableWorker` 管理可重做的异步工作。
|
|
|
-
|
|
|
-上层应用可以按需使用这些抽象组织异步任务与进度。
|
|
|
-
|
|
|
-### 3.3 配置
|
|
|
-
|
|
|
-`IConfigProvider` 定义读、写、删除、缓存丢弃等能力。默认 `JsonConfigProvider`:
|
|
|
-
|
|
|
-- 从 JSON 文件惰性读取;
|
|
|
-- 缓存反序列化后的值;
|
|
|
-- 通过 Worker 延迟 500 ms 合并写盘;
|
|
|
-- 使用 `ConfigEntry<T>` 提供固定 provider 的强类型配置;
|
|
|
-- 使用 `DynamicConfigEntry<T>` 支持运行时选择 provider。
|
|
|
-
|
|
|
-默认配置位于应用数据目录的 `config.json`,敏感配置 provider 指向 `secret.json`。加密写入目前仍有未实现分支,使用前需要核对现状。
|
|
|
-
|
|
|
-### 3.4 日志与通用类型
|
|
|
-
|
|
|
-库提供可替换的 Logger、并发列表、OneOf、值范围、数学和字符串工具等。上层应用可以替换 Logger 实例,将底层日志接入自身日志系统。
|
|
|
-
|
|
|
-## 4. 依赖
|
|
|
-
|
|
|
-- `Microsoft.Win32.Registry`:跨目标框架暴露注册表能力;
|
|
|
-- `Newtonsoft.Json`:配置与 JSON 工具;
|
|
|
-- `ThrottleDebounce`:限流/防抖基础;
|
|
|
-- `PolySharp`:为旧运行目标补足现代 C# 编译支持。
|
|
|
-
|
|
|
-## 5. 架构边界
|
|
|
-
|
|
|
-适合放入 MeloongCore 的代码应满足:
|
|
|
-
|
|
|
-- 不依赖具体上层应用的页面、全局状态或业务领域;
|
|
|
-- 不直接依赖 WPF 类型;
|
|
|
-- API 对其他 .NET 应用也有合理含义;
|
|
|
-- Windows 专属能力被清楚隔离,不阻塞 macOS 使用通用部分。
|
|
|
-
|
|
|
-WPF 特有实现应进入 `MeloongCore.Wpf`,上层应用特有实现应保留在对应应用仓库中。
|
|
|
-
|
|
|
-## 6. 优势与风险
|
|
|
-
|
|
|
-优势:
|
|
|
-
|
|
|
-- 目标框架和依赖方向支持跨项目复用;
|
|
|
-- 工具与配置已有对应测试;
|
|
|
-- 现代 C# API 提高了新代码的类型安全和可读性。
|
|
|
-
|
|
|
-风险:
|
|
|
-
|
|
|
-- 通用工具类较多,新增 API 时容易形成重复或过宽的职责;
|
|
|
-- 注册表等 Windows 能力出现在 Shared 中,需要保持调用层面的平台防护;
|
|
|
-- `JsonConfigProvider` 加密写入尚未实现完整;
|
|
|
-- 作为公共依赖修改时,需要考虑已有引用方的兼容性和独立发布节奏。
|
|
|
+# Shared 复用指南
|
|
|
+
|
|
|
+[代码约定](../仓库指示.md) · [Wpf](../Wpf/架构分析.md) · [Tests](../Tests/架构分析.md)
|
|
|
+
|
|
|
+## 按功能定位
|
|
|
+
|
|
|
+| 场景 | 源码入口 |
|
|
|
+| --- | --- |
|
|
|
+| 初始化、应用目录 | [Main.cs](../../Shared/Main.cs)、[PathUtils.cs](../../Shared/Utils/PathUtils.cs) |
|
|
|
+| 强类型键、JSON 配置 | [Config.cs](../../Shared/General/Config.cs) |
|
|
|
+| 日志接入 | [Logger.cs](../../Shared/General/Logger.cs) |
|
|
|
+| 分阶段进度 | [Progress.cs](../../Shared/General/Progress.cs) |
|
|
|
+| 节流、防抖、取消后重跑 | [Worker](../../Shared/General/Worker) |
|
|
|
+| 异步并发、进程执行 | [TaskUtils.cs](../../Shared/Utils/TaskUtils.cs) |
|
|
|
+| 并发列表、联合值、范围 | [ConcurrentList.cs](../../Shared/General/ConcurrentList.cs)、[OneOf.cs](../../Shared/General/OneOf.cs)、[ValueRange.cs](../../Shared/General/ValueRange.cs) |
|
|
|
+| 集合、字符串、异常、Task、HTTP 克隆扩展 | [Extensions](../../Shared/Extensions) |
|
|
|
+| 文件、目录、路径、压缩、校验 | [FileUtils.cs](../../Shared/Utils/FileUtils.cs)、[DirectoryUtils.cs](../../Shared/Utils/DirectoryUtils.cs)、[PathUtils.cs](../../Shared/Utils/PathUtils.cs) |
|
|
|
+| 格式化、数学、枚举、类型、加密 | [Utils](../../Shared/Utils) |
|
|
|
+| 注册表、Windows 增量补丁 | [RegistryUtils.cs](../../Shared/Utils/RegistryUtils.cs)、[MsDelta.cs](../../Shared/General/MsDelta.cs) |
|
|
|
+
|
|
|
+扩展方法主要位于 `MeloongCore.Extensions`,MathUtils、EnumUtils 的扩展位于 `MeloongCore`;项目全局 using 不传播到引用方。新框架同名方法可能改变重载绑定,替换前核对语义。注册表和 MsDelta 是 Windows 专属,Shared 的目标框架不代表所有入口均可跨平台使用。
|
|
|
+
|
|
|
+以下保留不易从名称判断的行为;具体重载和实现以链接源码为准。
|
|
|
+
|
|
|
+## 初始化、配置与日志
|
|
|
+
|
|
|
+- 首次访问默认配置前调用 `Main.Init(appName)`;它设置应用名和默认正则超时,不初始化 WPF 或文件日志。默认 provider 静态初始化后,修改应用名不会迁移其路径。
|
|
|
+- `ConfigEntry<T>` 绑定固定 provider,`DynamicConfigEntry<T>` 每次操作传 provider。替换 `ConfigProviders.Default` 不改变已有 entry 的绑定。
|
|
|
+- `ConfigProviders.Secret` 位于 `Paths.AppData/secret.json`,没有应用名子目录,也不自动加密。当前非 null 加密写入会先修改缓存再抛 `NotImplementedException`。
|
|
|
+- 同一 provider 的同一键固定使用同一类型;显式 JSON null 算已存值。Get 返回对象缓存,修改对象后需 Edit/Set 才安排保存;Edit 不是原子更新。
|
|
|
+- Set 即使值相同也触发 Changed;动态 entry 的 Changed 不携带 provider。PreviewGet 仅修正本次读取,不自动写回。
|
|
|
+- JSON 写入防抖 500 ms;明确落盘点可用 `ConfigUtils.SaveAll()`。DiscardCache 不保存变更;Save 写盘失败不保证恢复 dirty。整文件加载失败回退空对象,不代表所有键读取错误都会回退默认值。
|
|
|
+- `Logger.Instance` 可替换;基类不实现 LogBehavior 所表达的 UI 动作。BaseLogger 构造时启动后台线程并调用虚方法 Init;Output 通常在日志线程,HandleBehavior 在调用线程。
|
|
|
+- FileLogger 创建后修改路径字段可能晚于初始化;退出时先 Flush 再 Dispose,但尚未就绪时 Flush 会返回,Dispose 不保证排空或等待线程。
|
|
|
+
|
|
|
+## 进度与后台任务
|
|
|
+
|
|
|
+- ProgressProvider 用 SplitBy/SplitTo 分阶段;Reset 不清除单调观测历史,全新任务需要新 provider。Finish/Skip 可结算子项,IsFinished 不代表业务成功。
|
|
|
+- ProgressObserver 订阅并节流 GetIncreasing,构造时不立即刷新,结束时 Dispose;回调不保证 UI 线程。
|
|
|
+- RateLimitedWorker 的 ImmediateThenMerge 为节流,ImmediateThenIgnore 忽略密集后续请求,WaitUnillNoNewInvoke 为尾随防抖。复用同一实例;Dispose 不补执行最后一次。
|
|
|
+- RedoableWorker 在运行中 Start 会请求取消旧负载并合并重跑,负载必须协作取消。WaitIfRunning* 只等待空闲,不重抛负载错误,也不保证事件回调已结束。
|
|
|
+- RedoableWorker 的 HasSucceeded/LastResult 可保留历史成功,判断最近运行用 LastSucceeded;事件在工作线程。Worker 接受同步委托,不等待 async lambda 内的异步工作。
|
|
|
+- TaskUtils.WhenAll 聚合进度但不限并发;ForEach 是同步并行,异步限并发用 ForEachAsync。后者失败会停止领取新项,但内部取消令牌不传入 body,在途动作需自行响应外部令牌。
|
|
|
+- RunProgramAsync 返回 Output/ExitCode,非零退出码不自动抛错;输出按 stdout + stderr 拼接。取消/超时不保证终止子进程树;参数会写日志,不应包含密钥。
|
|
|
+
|
|
|
+## 数据结构与扩展语义
|
|
|
+
|
|
|
+- ConcurrentList 单次操作加锁,复合操作需共用 SyncRoot;枚举及与 List 的转换都复制列表,元素仍共享引用。
|
|
|
+- OneOf 的 default 没有有效分支;Is<T> 按声明类型精确匹配,取错分支会抛错。
|
|
|
+- ValueRange.Intersect 无交集仍返回范围,应检查 IsEmpty;IsEmpty 不识别离散域空区间。范围可变,不应修改已作为字典键的实例。
|
|
|
+- EnumerableExtensions 的并行 DistinctBy 不保证首项,重复枚举沿用已见键;MaxBy/MinBy 空输入返回 default;二维数组 ToDictionary 重复键以后者覆盖。
|
|
|
+- RemoveIf/KeepIf 原地修改;RemoveAll 对每项仅移除一次;Except(单值) 还会去重;ForAll 立即顺序枚举且不等待 async lambda。
|
|
|
+- 字符串 Before/After 系列未找到分隔符时保留原文;Between 从最后一个起始分隔符之后截取,不做括号配对。Split 去空模式对空串返回空数组,SplitLines 不修剪行内空白。
|
|
|
+- RegexSearch 的惰性枚举仍可能抛超时;RegexSeek/RegexCheck 捕获失败,而 RegexReplace 直接抛错。
|
|
|
+- ReadString 不关闭输入流;默认 GetString 尝试 BOM、严格 UTF-8,再回退 GB18030。DeserializeJson<T> 用于 JToken 子类,解析错误可能包含原文。
|
|
|
+- ExceptionExtensions.IsCanceled 对混有其他错误的聚合也可返回 true;RootException 只沿单条 InnerException,Flatten 扩展与 AggregateException 同名实例方法含义不同。ThrowIfCanceled 不保证保留原堆栈;IsBadNetwork 可能把主动取消判为网络不佳。
|
|
|
+- TaskExtensions.Run 同步阻塞;NoCapture 仅为 ConfigureAwait(false),不保证切到后台线程。
|
|
|
+- HTTP CloneAsync 缓冲复制全部内容,Properties 中的对象仍共享;无取消令牌重载。WebUtils.cs 定义 HttpRequestCodeException,未提供自动发送或失败状态检查。
|