Skip to content

技术规范 ​

本文档用于说明 PCL CE 启动器开发过程中应遵循的基础规范,包括命名规范、项目开发规范、提交信息规范以及文件格式要求等内容。

🚧 文档尚未完善

本文仍在完善中,欢迎开发者提交 PR 补充或修正文档内容。

规范用语说明 ​

本文中的规范性用语含义如下:

用语含义
必须 / 不得强制要求,提交内容应严格遵守
应 / 不应默认要求,除非有明确理由,否则应遵守
建议 / 推荐非强制要求,但通常有助于提升可维护性
可以允许的做法,可根据实际情况选择

基本命名规范 ​

命名规范的目标是提高代码可读性,使开发者可以直接从名称判断符号的作用域、类型或用途,减少对 IDE 上下文提示的依赖,并尽可能避免因作用域或类型混淆导致的问题。

PCL CE 代码库中仍存在部分历史遗留的不规范命名。新增代码应优先遵循本文规范;修改旧代码时,应在不引入额外风险的前提下逐步修正。

变量、字段、属性与事件 ​

本节适用于局部变量、参数、字段、属性、事件等可绑定或保存值的符号。除非特别说明,下表中的成员均指非静态成员。

类别命名规范示例
局部变量、方法参数、构造器参数camelCasename runningThread resourceMap
私有属性、私有只读字段_PascalCase_Items _PageMap
私有字段、静态私有字段_camelCase_parameters _runningThreads _hasDisposed
主构造器属性(record)、事件及其他成员PascalCaseName CurrentThread ActivePageCollection

提示

此处的“字段”包含部分历史文档或旧代码中称为“全局变量”的成员级变量。

方法 ​

本文将面向对象中的函数类型成员统一称为方法。除局部函数外,大多数托管式面向对象语言中的函数通常都以方法形式存在。

类别命名规范示例
非私有方法、静态非私有方法、局部方法PascalCaseStart() ComposeMessage() WriteLogItem()
私有方法_PascalCase_StartInternal() _RaiseChanged()

类型 ​

类型包括但不限于类、接口、枚举、记录、委托等可以作为类型使用的符号。

类别命名规范示例
接口IPascalCaseICollection ILifecycleService IConfig
其他类型PascalCaseLaunchProfile 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 工具辅助开发。AI 工具不能代替贡献者完成理解、审查和验证工作;贡献者必须对自己提交的全部内容负责。所有生成式 AI 使用情况均须披露,AI 辅助内容适用与其他贡献相同的质量标准。

使用 AI 工具时,应遵循 生成式人工智能使用方针。该方针规定了披露方式、贡献质量要求、审查流程、AI Agent 使用限制以及违规处理等内容;与 AI 使用相关的具体要求以该方针为准,本规范不再重复展开。

生命周期与服务 ​

生命周期管理 ​

生命周期系统的基本概念参见 生命周期简介。

调用服务相关内容时,必须确保被调用服务已经完成初始化。若调用顺序无法保证,可能会引发 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 标题。

text
type(scope?): digest

各字段含义如下:

字段要求
type必须使用英文小写,表示提交类型
scope可选,应使用英文说明影响的模块或子系统
digest应使用中文概括提交内容,并以动词原型开头

scope 应使用英文小写。若包含多个单词,应使用短横线连接,例如 profile、lifecycle、java-manage、rpc。

digest 应说明提交具体做了什么。必要的专业名词可以使用英文。推荐写法包括:

text
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 不应使用以下写法:

  • 过去时或将来时;
  • 单纯的名词短语;
  • 含糊不清、无法看出具体关联的描述;
  • 末尾句号。

错误示例:

text
docs: 深色模式
fix: 更正了 typo
imp: 一个高占用功能现在会默认关闭

推荐写法:

text
docs: 补充深色主题适配说明
fix: 更正下载页面的 NeoForge 拼写错误
imp: 默认关闭资源扫描中的高占用检查

一个清晰的 digest 通常不应超过 30 个汉字或 50 个英文字母。

多行格式 ​

多行格式适用于需要详细说明修改内容的提交信息。

text
type(scope?): subject

body

footer

第一行的规则与简单格式基本一致,但 subject 不需要完整展开所有细节。

body 用于详细描述提交内容,应包含修改动机,以及与之前行为的差异。

footer 可包含破坏性改动、合作作者信息或关联 issue。若没有对应内容,可以省略。

关联 issue 可使用以下格式:

text
Close #234
Close #234, #114, #514

若存在破坏性改动,应在 footer 中明确说明。

回滚提交 ​

回滚某个提交或 PR 时,提交信息应以 revert: 开头。

text
revert: digest (hash)

其中:

字段说明
digest原提交信息首行
hash原提交节点 hash,或原 PR ID。PR ID 应以 # 开头

示例:

text
revert: feat(profile): 支持可选的高级材质 (#123)

杂项规范 ​

换行符与编码 ​

换行符与文件编码差异可能导致大量无意义更改,增加 review 和后期溯源成本。

新增文件必须使用以下格式:

项目要求
换行符LF
文件编码标准 UTF-8
BOM不附带 BOM

修改已有文件时,应尽量遵循原文件格式。若原文件使用不同换行符或编码,不应为了统一格式而产生大量无关 diff,以免与其他分支中的修改产生冲突。

因换行符或编码变化造成大量无意义更改的 PR,可能会被要求重新提交,严重时可能被直接关闭。

Git 换行符处理

Git 可以自动处理提交内容的换行符,一般不需要手动管理本地文件换行符。详情可参考 GitHub 文档页面。

Rider 编码设置

Rider 可以在设置中指定默认使用标准 UTF-8 编码。部分编辑器或 IDE 可能会自动添加 BOM,因此提交前应注意检查文件首行是否出现无意义更改。若文件首行产生异常 diff,通常需要检查是否被添加了 BOM。

Released under the Creative Commons Attribution-ShareAlike 4.0 International Public License (CC BY-SA 4.0).