技术规范
本文档用于说明 PCL CE 启动器开发过程中应遵循的基础规范,包括命名规范、项目开发规范、提交信息规范以及文件格式要求等内容。
🚧 文档尚未完善
本文仍在完善中,欢迎开发者提交 PR 补充或修正文档内容。
规范用语说明
本文中的规范性用语含义如下:
| 用语 | 含义 |
|---|---|
| 必须 / 不得 | 强制要求,提交内容应严格遵守 |
| 应 / 不应 | 默认要求,除非有明确理由,否则应遵守 |
| 建议 / 推荐 | 非强制要求,但通常有助于提升可维护性 |
| 可以 | 允许的做法,可根据实际情况选择 |
基本命名规范
命名规范的目标是提高代码可读性,使开发者可以直接从名称判断符号的作用域、类型或用途,减少对 IDE 上下文提示的依赖,并尽可能避免因作用域或类型混淆导致的问题。
PCL CE 代码库中仍存在部分历史遗留的不规范命名。新增代码应优先遵循本文规范;修改旧代码时,应在不引入额外风险的前提下逐步修正。
变量、字段、属性与事件
本节适用于局部变量、参数、字段、属性、事件等可绑定或保存值的符号。除非特别说明,下表中的成员均指非静态成员。
| 类别 | 命名规范 | 示例 |
|---|---|---|
| 局部变量、方法参数、构造器参数 | camelCase | name runningThread resourceMap |
| 私有属性、私有只读字段 | _PascalCase | _Items _PageMap |
| 私有字段、静态私有字段 | _camelCase | _parameters _runningThreads _hasDisposed |
| 主构造器属性(record)、事件及其他成员 | PascalCase | Name CurrentThread ActivePageCollection |
提示
此处的“字段”包含部分历史文档或旧代码中称为“全局变量”的成员级变量。
方法
本文将面向对象中的函数类型成员统一称为方法。除局部函数外,大多数托管式面向对象语言中的函数通常都以方法形式存在。
| 类别 | 命名规范 | 示例 |
|---|---|---|
| 非私有方法、静态非私有方法、局部方法 | PascalCase | Start() ComposeMessage() WriteLogItem() |
| 私有方法 | _PascalCase | _StartInternal() _RaiseChanged() |
类型
类型包括但不限于类、接口、枚举、记录、委托等可以作为类型使用的符号。
| 类别 | 命名规范 | 示例 |
|---|---|---|
| 接口 | IPascalCase | ICollection ILifecycleService IConfig |
| 其他类型 | PascalCase | LaunchProfile ConfigSource PageState |
特殊命名要求
| 类别 | 要求 |
|---|---|
| 事件 | 不应以 On 开头 |
AutoResetEvent、ManualResetEvent、ManualResetEventSlim 等事件同步对象 | 应以 Event 结尾 |
项目开发规范
本节说明项目开发中的标准用法和注意事项。新增代码应优先遵循本节要求;修改旧代码时,应在保持兼容性的前提下逐步迁移。
代码变更范围
每次提交或 PR 应尽量只处理一个问题或一类修改。若同时包含多个不相关的修改,会增加 review 难度,也不利于后续回滚和问题定位。
提交内容不应包含与本次修改无关的文件变更,包括但不限于:
- IDE 自动格式化产生的大量无关 diff;
- 与功能修改无关的缩进、空格、换行符调整;
- 本地配置文件、临时文件或构建产物;
- 未说明原因的批量重排、重命名或迁移。
若某些看似无关的修改确有必要,应在提交信息或 PR 描述中说明原因。
旧代码风格处理
修改已有文件时,应在符合规范的前提下尽量保留原有代码风格,包括缩进、空行、成员排列位置等,以减少无关 diff。
若原文件明显不符合本文规范,可以先单独提交一次格式修正,再在后续提交中进行功能修改。格式修正提交应使用 style 类型。
不应在功能提交中混入大量格式化修改。若功能修改与格式化修改混在一起,维护者可能会要求拆分提交。
可维护性要求
新增代码应优先保证可读性和可维护性,不应为了减少行数或追求技巧性写法而牺牲清晰度。
以下写法应尽量避免:
- 过深的嵌套逻辑;
- 难以判断状态来源的隐式副作用;
- 重复实现项目中已有的工具方法;
- 为单一场景引入过度复杂的抽象;
- 无必要的全局状态或静态可变状态;
- 没有明确生命周期管理的后台任务、事件订阅或资源占用。
若新增逻辑较复杂,应通过合理拆分方法、添加必要注释或补充测试来降低维护成本。
goto 与代码标签
不得在新增代码中使用 goto 语句和代码标签,除非该场景存在非常明确且无法替代的技术理由。
如果某个功能看起来只能通过 goto 实现,通常说明流程设计需要重新整理。由于跳转结构维护成本较高,包含 goto 的 PR 很可能会被维护者拒绝。
测试与提交前检查
与业务逻辑有关的代码,应在本地完成基本测试后再提交。仅修改文档、注释或 README 等文本内容时,可以根据修改范围决定是否需要运行完整测试。
提交前应至少检查以下内容:
- 项目能否正常构建;
- 修改过的功能是否能基本运行;
- 是否存在与本次修改无关的文件变更;
- 是否误提交临时文件、构建产物或本地配置;
- 提交信息是否符合本文的提交信息规范;
- 所有提交是否附带已验证签名。
若使用 IDE 或图形化 Git 工具提交,也应在提交前逐个文件检查 diff,确认所有变更都属于本次修改范围。
AI 工具使用规范
项目允许贡献者合理使用 AI 工具,例如 GitHub Copilot、ChatGPT、DeepSeek、Claude 等,以提升开发效率。
AI 只能作为辅助工具。提交者必须理解、审查并维护自己提交的全部内容,不得将未经确认的 AI 生成结果直接作为最终代码提交。
重要
若 PR 不符合本节要求,维护者可能会关闭该 PR。若多次提交不符合要求的 PR,维护者有权限制相关贡献者继续参与仓库活动。
注明使用的模型及版本
若提交内容包含 AI 生成或 AI 实质性改写的代码,提交者必须明确注明所使用的模型及版本。
可以在提交信息末尾或 PR 标题末尾添加模型标识,例如:
[DeepSeek-V3.2]
[Claude-Opus-4.6]
[GPT-5.1]示例:
fix(scope): 修复某功能在特定情况下的异常 [GPT-5.1]若同一 PR 中使用了多个模型,应在 PR 描述中说明各模型的大致用途。
禁止直接提交 AI 生成的大型 PR
大型 PR 的判定标准如下:
- 一次性新增或修改代码超过 200 行;
- 或一次性修改超过 5 个
.cs或.xaml文件。
对于此类 PR,不得将 AI 生成的代码未经拆分、理解和重构就直接提交。
提交者应将大型任务拆分为多个较小的提交,并确保每一处逻辑变更都已被人工理解、审查和验证。否则,维护者可能会拒绝或关闭该 PR。
禁止提交未审查的低质量 AI 代码
AI 生成的代码可能存在虚构 API、逻辑漏洞、重复造轮子、过度设计、风格不一致或性能问题。提交者必须自行审查并修正这些问题。
提交前应至少检查以下内容:
- 代码风格是否符合本文规范;
- 是否存在未处理的
TODO注释; - 是否使用了不存在的 API、参数或类型;
- 是否重复实现了项目中已有的工具;
- 是否引入了不必要的依赖;
- 是否存在明显性能问题;
- 设计是否过度复杂;
- 是否能够解释新增代码的实现思路和行为边界。
维护者没有义务帮助提交者审查未经整理的 AI 生成代码。若代码明显由 AI 生成且缺乏人工审查痕迹,相关 PR 可能会被直接关闭。
生命周期与服务
生命周期管理
生命周期系统的基本概念参见 生命周期简介。
调用服务相关内容时,必须确保被调用服务已经完成初始化。若调用顺序无法保证,可能会引发 NullReferenceException、InvalidOperationException 等异常。
对于同步服务,应满足以下条件之一:
- 在更晚的生命周期状态中调用;
- 在相同生命周期状态的异步服务初始化中调用;
- 在相同生命周期状态中,由优先级更低的同步服务初始化逻辑调用。
对于异步服务,只应在更晚的生命周期状态中调用,不应在相同生命周期状态中假定其已经完成初始化。
配置系统
配置系统的基本概念参见 应用配置系统简介。
为方便维护,新增配置项应尽可能统一声明在核心库的 Config.cs 文件中,并为配置项添加必要注释。
若可以明确确认某个配置项只在单一体系内部使用,则可以在该体系内部声明。
注册配置项事件前,应确认事件处理逻辑具有足够好的性能。配置系统的所有事件都会同步执行,以保证配置值的全局一致性。因此,性能较差、耗时较长或可能阻塞的事件处理逻辑会直接影响配置读写流程。
编译期代码生成优化
新增代码应尽可能使用 .NET 提供的编译期源生成能力,减少运行时反射、动态初始化和重复编译带来的开销。
正则表达式
.NET 7 引入了 GeneratedRegexAttribute,用于在编译期预生成正则表达式匹配逻辑,以提升运行时性能。
新增的正则匹配逻辑应遵循以下要求:
- 新增的非既有体系正则匹配必须使用
GeneratedRegex; - 不应动态初始化可静态确定的正则表达式;
- 新增的正则参数方法,除非有特殊需求,否则应接收
Regex实例,而不是接收字符串形式的正则表达式; - 推荐将新的正则表达式声明添加到核心库的
Utils/RegexPatterns.cs文件中。
GeneratedRegex 的规范用法可参考核心库中的 Utils/RegexPatterns.cs。
外部库调用(P/Invoke)
.NET 7 引入了 LibraryImportAttribute,用于在编译期预生成静态封送代码,并使 P/Invoke 调用可以被 inline 优化。
新增 P/Invoke 调用应遵循以下要求:
- 必须使用
LibraryImport替代DllImport; - 使用
LibraryImport时,应使用partial关键字,而不是extern; - 推荐优先使用静态封送特性;
- 在适合的场景中,可以使用
Span<T>等类型安全地处理指针导出数据,以提高安全性和性能; - 除非确有必要,不应将 P/Invoke 声明暴露到当前类范围之外。
提示
LibraryImport 要求方法使用 partial 关键字;DllImport 常见写法中的 extern 不适用于该模式。
提示
官方示例中 P/Invoke 声明的可见性可以放宽到 internal,但为了提升可维护性,项目中仍推荐将 LibraryImport 声明为 private。
提交信息规范
提示
本节部分内容来自仓库原 CONTRIBUTING.md 文件,感谢原作者 @WorldHim、@wyc-26、@3gf8jv4dv 的贡献。
提交签名要求
PCL CE 仓库要求 PR 中的所有提交都附带已验证签名。
提交者应使用 GitHub 支持的 GPG 签名或 SSH 签名,并确保提交邮箱与 GitHub 账户中已验证的邮箱一致。
未附带已验证签名的提交可能无法合并。若提交显示为 Unverified,应先修复签名配置,再重新提交或修正提交历史。
简单格式
简单格式适用于单行提交信息和 PR 标题。
type(scope?): digest各字段含义如下:
| 字段 | 要求 |
|---|---|
type | 必须使用英文小写,表示提交类型 |
scope | 可选,应使用英文说明影响的模块或子系统 |
digest | 应使用中文概括提交内容,并以动词原型开头 |
scope 应使用英文小写。若包含多个单词,应使用短横线连接,例如 profile、lifecycle、java-manage、rpc。
digest 应说明提交具体做了什么。必要的专业名词可以使用英文。推荐写法包括:
feat(profile): 支持可选的高级材质
fix(java-manage): 修复 Java 8 及以前的版本无法被正确识别
imp(rpc): 默认启用 RPC 服务提示
scope 后面的冒号与 digest 之间必须保留一个空格。
提交类型
| 类型 | 说明 |
|---|---|
feat / feature | 引入新特性。通常是用户可感知的更改,例如深色模式、Java 管理;也可以是仅开发者可感知的能力,例如引入生命周期管理 |
fix | 修复线上或开发中发现的 bug,使程序行为恢复预期 |
imp / improve | 优化现有功能的交互体验、可读性等,通常是用户可感知的更改 |
ref / refactor | 重构现有代码结构或实现方式,不大幅改变外部功能,主要改善可维护性 |
docs | 仅修改文档内容,例如 README、注释、API 文档等,不涉及程序逻辑 |
style | 与功能无关的代码格式调整,包括但不限于空格、缩进、分号、命名风格等 |
perf / performance | 专门针对性能的优化,例如算法改进、缓存方案、渲染优化等 |
test | 添加或修改单元测试、集成测试、测试脚本等 |
chore | 构建流程维护、依赖升级、项目配置调整等与业务逻辑无关的杂项 |
bump | 版本相关更改,例如发布新 release 版本 |
ci | 修改 CI/CD 配置文件、自动化脚本、构建管道等 |
提交类型应尽量选择最贴近修改内容的类型。部分类型较为泛用,但在存在更具体分类时,不应使用泛用分类。
例如:
- 修复 CI 构建失败时,应使用
ci,而不是fix; - 修复可通过提升设备性能缓解的问题时,应优先考虑是否属于
perf; - 修改构建配置或添加依赖项时,应使用
chore,而不是feat。
digest 编写要求
digest 应简洁、明确,并能直接看出本次提交的实际修改内容。
digest 不应使用以下写法:
- 过去时或将来时;
- 单纯的名词短语;
- 含糊不清、无法看出具体关联的描述;
- 末尾句号。
错误示例:
docs: 深色模式
fix: 更正了 typo
imp: 一个高占用功能现在会默认关闭推荐写法:
docs: 补充深色主题适配说明
fix: 更正下载页面的 NeoForge 拼写错误
imp: 默认关闭资源扫描中的高占用检查一个清晰的 digest 通常不应超过 30 个汉字或 50 个英文字母。
多行格式
多行格式适用于需要详细说明修改内容的提交信息。
type(scope?): subject
body
footer第一行的规则与简单格式基本一致,但 subject 不需要完整展开所有细节。
body 用于详细描述提交内容,应包含修改动机,以及与之前行为的差异。
footer 可包含破坏性改动、合作作者信息或关联 issue。若没有对应内容,可以省略。
关联 issue 可使用以下格式:
Close #234
Close #234, #114, #514若存在破坏性改动,应在 footer 中明确说明。
回滚提交
回滚某个提交或 PR 时,提交信息应以 revert: 开头。
revert: digest (hash)其中:
| 字段 | 说明 |
|---|---|
digest | 原提交信息首行 |
hash | 原提交节点 hash,或原 PR ID。PR ID 应以 # 开头 |
示例:
revert: feat(profile): 支持可选的高级材质 (#123)杂项规范
换行符与编码
换行符与文件编码差异可能导致大量无意义更改,增加 review 和后期溯源成本。
新增文件必须使用以下格式:
| 项目 | 要求 |
|---|---|
| 换行符 | LF |
| 文件编码 | 标准 UTF-8 |
| BOM | 不附带 BOM |
修改已有文件时,应尽量遵循原文件格式。若原文件使用不同换行符或编码,不应为了统一格式而产生大量无关 diff,以免与其他分支中的修改产生冲突。
因换行符或编码变化造成大量无意义更改的 PR,可能会被要求重新提交,严重时可能被直接关闭。
Git 换行符处理
Git 可以自动处理提交内容的换行符,一般不需要手动管理本地文件换行符。详情可参考 GitHub 文档页面。
Rider 编码设置
Rider 可以在设置中指定默认使用标准 UTF-8 编码。部分编辑器或 IDE 可能会自动添加 BOM,因此提交前应注意检查文件首行是否出现无意义更改。若文件首行产生异常 diff,通常需要检查是否被添加了 BOM。
