UnityStarter 内置一套名为 CycloneGames.Analyzers 的 Roslyn 分析器(Roslyn Analyzer)模块,相当于 Unity 项目的"代码质量守门人":它在编译期自动扫描代码,把 GC 分配、GameObject.Find、async void 这类隐患拦在提交之前。本文整理出全部 24 条已实现规则的完整清单,帮你快速掌握这套 Unity 代码质量工具的规则体系。
分析器是什么:编译期就把隐患拦住
传统做法是等运行时卡帧、出 Bug 了再回头排查;而 UnityStarter 的 Roslyn 分析器把检查前移到编译期——只要代码不符合团队约定,Unity 编辑器打开时错误窗口(Error Window)就会给出提示,甚至直接报编译错误。
模块位于 UnityStarter/Analyzers/CycloneGames.Analyzers/,规则定义集中在:
- 规则 ID 声明:DiagnosticIds.cs
- 规则描述与默认严重级别:DiagnosticRules.cs
- 五大规则分类:DiagnosticCategories.cs
- 中文说明文档:README.SCH.md
项目还自带一套真实编译验证工具(CycloneGames.Analyzers.Verifier/),会在隔离的临时 Unity 工程中实际编译一段违规代码,确认分析器真的能触发诊断,而不是"纸面规则"。
24 条规则完整清单:按 5 大分类速查
所有规则 ID 统一以CG开头。DiagnosticIds共声明 28 个 ID,其中24 条已实现、4 条为预留(详见文末)。
1️⃣ 性能类(CycloneGames.Performance):守护热路径
| ID | 规则 | 触发场景 | 默认级别 |
|---|---|---|---|
| CG0001 | 热路径中的foreach | IL2CPP 下枚举器可能产生分配,建议改for索引循环 | Warning |
| CG0002 | 热路径中的 LINQ | LINQ 会产生临时可枚举对象/委托 | Warning |
| CG0003 | 热路径中的字符串构造 | 插值、string.Format、拼接都会分配 | Warning |
| CG0004 | 热路径中的Camera.main | 本质是隐藏的FindGameObjectWithTag场景搜索 | Warning |
| CG0041 | 链式component.transform访问 | 每次访问都是 native 互调,应缓存 Transform | Warning |
| CG0043 | 热路径中的Debug.Log | 每帧打印既分配又拖慢 | Warning |
| CG0044 | 热路径中的GetComponent<T> | 昂贵的 native 互调,应缓存结果 | Warning |
| CG0045 | 热路径中的装箱转换 | 值类型赋给 object/接口会触发装箱 | Warning |
| CG0046 | 热路径中的 lambda / 匿名方法 | 可能分配委托 | Warning |
2️⃣ 安全类(CycloneGames.Safety):禁止危险 API
| ID | 规则 | 为什么危险 | 默认级别 |
|---|---|---|---|
| CG0010 | 生产代码中的GameObject.Find | 脆弱且慢,应使用序列化引用、DI 或注册表 | Error |
| CG0011 | 场景级FindObjectOfType系列 API | O(n) 全场景搜索 | Error |
| CG0012 | SendMessage/BroadcastMessage | 基于字符串、无编译期安全 | Error |
| CG0013 | MonoBehaviour.Invoke系列 API | 字符串方法查找,建议改UniTask.Delay或显式计时器 | Error |
| CG0014 | Resources.Load | 绕过项目资产管理管线(资产管线 Provider 实现可语义豁免) | Warning |
3️⃣ 规范类(CycloneGames.Convention):保持代码风格
| ID | 规则 | 说明 | 默认级别 |
|---|---|---|---|
| CG0030 | MonoBehaviour上的 public 实例字段 | 建议[SerializeField] private+ 属性;嵌套 struct/普通 class 不误报 | Warning |
| CG0031 | Runtime 代码中的using static | 降低可读性,要求显式限定类型 | Warning |
| CG0032 | Runtime 代码中的#region | 常掩盖糟糕的组织方式,建议拆小类型 | Info(默认关闭) |
| CG0033 | 框架代码中的[Obsolete] | 框架 API 直接删除并更新调用方,不留废弃接口 | Warning |
4️⃣ API 契约类(CycloneGames.ApiContract):统一日志契约
| ID | 规则 | 说明 | 默认级别 |
|---|---|---|---|
| CG0049 | 绕过统一日志 API | 受治理的程序集禁止直接调用Debug.Log*、print、Console.Write*等,必须走日志门面 | Error |
| CG0050 | 日志门面之外调用LogChannel.Create | 每个程序集只允许一个可发现的日志门面边界 | Error |
这两条规则守护的是 UnityStarter 的统一日志系统——所有模块的日志都收敛到各自的 assembly log facade(例如CycloneGames.Audio.Runtime的Diagnostics/AudioRuntimeLog.cs),由门面统一投递到 Unity Console、文件等 sink。效果上,Console 里每条日志都带分类标签且可点击跳转到源码行:
官方说明:两条日志规则刻意不提供 CodeFix——因为安全替换涉及模块分类、异常上下文、延迟格式化等决策,单个调用点无法推断(见 README.SCH.md 第 121 行附近的说明)。
5️⃣ Unity 最佳实践类(CycloneGames.UnityBestPractices)
| ID | 规则 | 说明 | 默认级别 |
|---|---|---|---|
| CG0040 | Runtime 代码中的async void | 异常无法捕获,建议async UniTask | Error |
| CG0042 | Editor 目录外使用UnityEditor命名空间 | 应移入 Editor 代码或包UNITY_EDITOR | Warning |
| CG0047 | 引用 UniTask 时使用async Task | Task是 class 必分配,UniTask是 struct 可池化 | Warning |
| CG0048 | 静态类循环依赖风险 | 通过调用链成环检测,建议拆出非静态帮助类 | Warning |
分阶段强制策略:从 Warning 到 Error 的平滑迁移
规则不是"一刀切"。项目通过 Assets 根目录的 Default.ruleset(Unity 会自动应用到全工程)管理强制策略:
| 规则 | 策略 |
|---|---|
| CG0010 | 保持Error,生产代码零容忍 |
| CG0011 / CG0013 | 暂降为Warning——存量调用点迁移完成前,避免"启用分析器 = 编译中断" |
这份策略文件由契约测试(UnityActivationArtifactTests.cs)守护:只有当 owning 模块还清迁移债,才允许把 Warning 提升为 Error。此外,CG0010/CG0011对Editor/、Tests/、Samples/目录下的代码保持沉默——编辑器工具和测试里做场景扫描是合法行为。
附赠能力:2 个 CodeFix 一键修复
并非所有规则都只有"报错",以下两条支持一键修复(源码见 CodeFixes/):
| 诊断 | 修复动作 |
|---|---|
| CG0001 | 集合具备Count/Length和 int 索引器时,自动把foreach转换为for索引循环(ForEachToForCodeFix.cs) |
| CG0004 | 自动新增缓存的Camera字段并在Awake中赋值,替换热路径里的Camera.main(CameraMainCachingCodeFix.cs) |
热路径怎么算?别误伤
热路径规则只针对每帧执行的方法,默认命中以下方法名:
Update, LateUpdate, FixedUpdate, OnGUI, Tick, OnTick, OnUpdate, PreUpdate, PostUpdate, OnPreTick, OnPostTick设计原则是宁可漏报、不可误报——大范围误报只会逼着团队去禁用分析器,那才是对代码质量最大的伤害。
如何在项目中启用与调整规则
- 确认激活:项目已通过 Assets/Analyzers/CycloneGames.Analyzers.dll 及其
.meta(带RoslynAnalyzer标签)激活,模板开箱即用。 - 调整 Unity 编译严重级别:修改 Default.ruleset,例如
<Rule Id="CG0011" Action="Warning" />。 - 兼容 IDE / 独立 .NET 宿主:用
.editorconfig,例如dotnet_diagnostic.CG0001.severity = error。 - 局部抑制要克制:仅当分配或 API 成本是有意行为并记录原因时,才使用
#pragma warning disable CG00xx包裹。
一条新规则要"默认启用"还需过质量门槛:语义级检查(而非脆弱的字符串匹配)、正例反例测试齐全、对现有 UnityStarter 模块零/低误报、改写安全才配 CodeFix。
预留规则:4 个已占位的 ID
以下 ID 已在 DiagnosticIds.cs 中声明但尚未实现,属于规划中的规则:
CG0015:NativeContainerLeak(原生容器泄漏)CG0022:ActorStartBaseCall(重写Actor.Start必须调用base.Start(),否则BeginPlay()不触发)CG0023:PoolOnDespawnOverride(FastObjectPool子类必须重写OnDespawn,防止池化对象状态泄漏)CG0024:GameplayTagImplicitCast(GameplayTag 的字符串隐式转换应先校验)
这 4 条在 DiagnosticRules.cs 中已写好诊断描述,属于"规则先行、实现待补"的预留位,也说明这套规则清单还在持续演进。
总结
UnityStarter 的 Roslyn 分析器把"零 GC 热路径、安全 API、统一日志、框架规范"四大主题拆成 24 条可执行规则,用编译期强制替代事后救火,配合分阶段升级策略避免存量代码被"误伤"。对新手来说,读懂这份清单,也就读懂了这个框架对代码质量的期待。
📎 延伸资料:
- 规则总览(英文):README.md
- 分析器测试用例:CycloneGames.Analyzers.Tests/
- 统一日志包说明:CycloneGames.Logging.Unity/README.SCH.md
【免费下载链接】UnityStarter
Production-ready modular Unity framework: UE-inspired Gameplay Ability System, zero-GC core, HybridCLR hot-update, Luban config pipeline,>项目地址:https://gitcode.com/gh_mirrors/un/UnityStarter
相关推荐
5分钟掌握Balena Etcher:开源镜像烧录工具的终极使用指南
5分钟掌握Balena Etcher:开源镜像烧录工具的终极使用指南 在嵌入式开发、单板计算机系统部署和操作系统安装过程中,镜像烧录工具是每个开发者必备的利器。
桌面应用嵌入式开发工具Simple Icons代码质量保障:ESLint规则与代码审查清单
Simple Icons代码质量保障:ESLint规则与代码审查清单 在开源项目开发中,代码质量是项目可持续发展的基石。Simple Icons作为一个专注于提
前端UI组件pi-subagents 未来展望:AI 代理编排技术的发展趋势
pi subagents 未来展望:AI 代理编排技术的发展趋势 pi subagents 作为一款专注于异步子代理委托的 Pi 扩展,通过任务截断、成果物管理
人工智能AI Agent多智能体Agent 编排代码智能体AI 技能