mcpField
T
theone-unity-standards

theone-unity-standards

github.com/the1studio开发41 次安装
代码仓库

关于 theone-unity-standards

面向 Unity 6 与 C# 9 项目的开发和代码审查技能,按代码质量、现代 C# 模式、架构及性能设定规范。它提供 VContainer 或 TheOne.DI 等架构指引及审查清单。

主要功能

  1. 01可空类型与警告处理规范
  2. 02现代 C# 编码模式指引
  3. 03依赖注入与事件架构规范
  4. 04通过 Controller 访问数据
  5. 05Unity 性能与代码审查清单

适用场景

  1. 01编写或重构 Unity C# 代码
  2. 02审查代码变更与拉取请求
  3. 03设置项目依赖注入和事件架构
  4. 04检查资源释放与热路径分配

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/the1studio/theone-training-skills --skill theone-unity-standards

安装后在 Claude Code 中输入/theone-unity-standards确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/csharp/
linq-patterns.md
modern-csharp-features.md
performance-optimizations.md
quality-hygiene.md
references/review/
architecture-review.md
csharp-quality.md
performance-review.md
unity-specifics.md
references/unity/
data-controllers.md
integration-patterns.md
signalbus-events.md
theone-framework.md
unitask-patterns.md
vcontainer-di.md

详细介绍

TheOne Studio Unity 开发规范

⚠️ **Unity 6(C# 9):**所有模式和示例均兼容 Unity 6,该版本使用 C# 9。不会使用 C# 10+ 功能。

技能用途

此技能以 代码质量优先 为原则,贯彻 TheOne Studio 全面的 Unity 开发规范:

优先级 1:代码质量与规范(最重要)

  • 可空引用类型、访问修饰符、修复所有警告
  • 抛出异常(绝不记录错误日志)
  • TheOne.Logging.ILogger(运行时,不设保护、不加前缀、不在构造函数中记录日志)与 Debug.Log(仅限编辑器)
  • readonly/const、nameof、using 指令作用域
  • 不写行内注释(使用描述性名称)

优先级 2:现代 C# 模式

  • 优先使用 LINQ 而不是循环、扩展方法、表达式体
  • 空合并运算符、模式匹配
  • 现代 C# 功能(records、init、with)

优先级 3:Unity 架构

  • VContainer + SignalBus 或 TheOne.DI + Publisher/Subscriber
  • Data Controllers 模式(绝不直接访问数据)
  • 资源管理、UniTask 异步模式

优先级 4:性能与审查

  • LINQ 优化、避免分配
  • 代码审查指南

此技能的触发场景

  • 编写或重构 Unity C# 代码
  • 使用依赖注入实现 Unity 功能
  • 处理事件和信号
  • 访问或修改游戏数据
  • 审查代码变更或拉取请求
  • 设置项目架构

快速参考指南

需要哪方面的帮助?
优先级任务参考资料
🔴 优先级 1:代码质量(首先检查)
1可空类型、访问修饰符、警告、异常代码质量与规范 ⭐
1TheOne.Logging.ILogger(不设保护、不加前缀、不在构造函数中记录日志)与 Debug.Log代码质量与规范 ⭐
1readonly/const、nameof、using 作用域、不写行内注释代码质量与规范 ⭐
🟡 优先级 2:现代 C# 模式
2LINQ、扩展方法、var 的用法LINQ 模式
2表达式体、空合并、模式匹配现代 C# 功能
2Records、init、with 表达式现代 C# 功能
🟢 优先级 3:Unity 架构
3VContainer 依赖注入VContainer DI
3SignalBus 事件系统SignalBus 事件
3Data Controllers 模式(绝不直接访问数据)Data Controllers
3Service/Bridge/Adapter 集成集成模式
3TheOne.DI + Publisher/Subscriber 替代方案TheOne 框架
3UniTask 异步/await 模式UniTask 模式
🔵 优先级 4:性能与审查
4性能、LINQ 优化、内存分配性能
4架构审查(DI、事件、控制器)架构审查
4C# 质量审查(LINQ、空值处理)C# 质量
4Unity 专项审查(组件、生命周期)Unity 专项
4性能审查(内存分配、热点路径)性能审查

🔴 关键:代码质量规则(首先检查!)

⚠️ 强制质量标准

始终在编写任何代码之前落实以下要求:

  1. 启用可空引用类型 - 不允许有可空性警告
  2. 使用最低限度的访问修饰符 - 默认使用 private
  3. 修复所有警告 - 对编译器警告零容忍
  4. 出错时抛出异常 - 绝不记录错误日志,改为抛出异常
  5. 运行时使用 TheOne.Logging.ILogger - 不使用条件保护(#if)、不添加前缀([prefix])、绝不在构造函数中使用;仅在编辑器脚本中使用 Debug.Log
  6. 字段使用 readonly - 标记不会重新赋值的字段
  7. 常量使用 const - 常量应使用 const,而非 readonly
  8. 字符串使用 nameof - 绝不硬编码属性名或参数名
  9. 在最深层作用域中使用 using 指令 - 尽可能在方法级别使用 using
  10. 不写内联注释 - 使用描述性名称;代码应能自我说明

示例:优先落实质量标准

// ✅ EXCELLENT: All quality rules enforced
#nullable enable // 1. Nullable enabled

public sealed class PlayerService
{
    private readonly TheOne.Logging.ILogger logger;
    private const int MaxHealth = 100;

    public PlayerService(TheOne.Logging.ILogger logger)
    {
        this.logger = logger;
    }

    public Player GetPlayer(string id)
    {
        using System.Text.Json;

        return players.TryGetValue(id, out var player)
            ? player
            : throw new KeyNotFoundException($"Player not found: {id}");
    }

    private void LoadGameData()
    {
        this.logger.Info("Game data loaded");
    }
}

#if UNITY_EDITOR
public class EditorTool
{
    public void Process()
    {
        Debug.Log("Processing..."); // 5. Debug.Log OK in editor
    }
}
#endif

⚠️ Unity 架构规则(质量标准之后)

选择一种框架技术栈

每个项目只选择一种技术栈:

选项 1:VContainer + SignalBus

  • ✅ 使用 VContainer 进行依赖注入
  • ✅ 使用 SignalBus 处理事件
  • ✅ 在构造函数上使用 [Preserve] 特性

选项 2:TheOne.DI + 发布者/订阅者

  • ✅ 使用 TheOne.DI 包装器
  • ✅ 使用 IPublisher/ISubscriber 处理事件
  • ✅ 在构造函数上使用 [Inject] 特性

通用规则(适用于两种技术栈):

  • ✅ 使用数据控制器(绝不直接访问数据)
  • ✅ 使用 UniTask 执行异步操作
  • ✅ 在 Dispose 中卸载资源
  • ✅ 运行时使用 TheOne.Logging.ILogger(不加保护、不添加前缀、不在构造函数中记录日志),仅在编辑器中使用 Debug.Log

简要示例

🔴 质量优先
// ✅ EXCELLENT: Quality rules enforced
#nullable enable

public sealed class PlayerController
{
    private readonly TheOne.Logging.ILogger logger;
    private const int MaxRetries = 3;

    public PlayerController(TheOne.Logging.ILogger logger)
    {
        this.logger = logger;
    }

    public Player LoadPlayer(string id)
    {
        if (!File.Exists(id))
            throw new FileNotFoundException($"Player file not found: {id}");

        this.logger.Info($"Loading player {id}");
        return DeserializePlayer(id);
    }
}

#if UNITY_EDITOR
public class EditorHelper
{
    public void Log() => Debug.Log("Editor only"); // Debug.Log OK in editor
}
#endif
🟡 现代 C# 模式
// ✅ GOOD: LINQ instead of loops
var activeEnemies = allEnemies.Where(e => e.IsActive).ToList();

// ✅ GOOD: Expression bodies
public int Health => this.currentHealth;

// ✅ GOOD: Null-coalescing
var name = playerName ?? "Unknown";

// ✅ GOOD: Pattern matching
if (obj is Player player) player.TakeDamage(10);
Unity 架构(VContainer)
using UnityEngine.Scripting;
using VContainer.Unity;

public sealed class GameService : IInitializable, IDisposable
{
    private readonly SignalBus signalBus;
    private readonly LevelDataController levelController;

    [Preserve]
    public GameService(SignalBus signalBus, LevelDataController levelController)
    {
        this.signalBus = signalBus;
        this.levelController = levelController;
    }

    void IInitializable.Initialize()
    {
        this.signalBus.Subscribe<WonSignal>(this.OnWon);
    }

    void IDisposable.Dispose()
    {
        this.signalBus.TryUnsubscribe<WonSignal>(this.OnWon);
    }
}
Unity 架构(TheOne.DI)
public sealed class GameService : IAsyncEarlyLoadable, IDisposable
{
    private readonly IPublisher<WonSignal> publisher;
    private IDisposable? subscription;

    [Inject]
    public GameService(
        IPublisher<WonSignal> publisher,
        ISubscriber<WonSignal> subscriber)
    {
        this.publisher = publisher;
        this.subscription = subscriber.Subscribe(this.OnWon);
    }

    public void Dispose()
    {
        this.subscription?.Dispose();
    }
}

代码审查清单

快速验证(提交前)

🔴 代码质量(首先检查):

  • 已启用可空引用类型(#nullable enable)
  • 所有访问修饰符均正确(默认使用 private)
  • 编译器警告为零
  • 出错时抛出异常(不记录错误日志)
  • 区分 TheOne.Logging(运行时)和 Debug.Log(仅限编辑器)
  • 不会重新赋值的字段使用 readonly
  • 常量使用 const
  • 使用 nameof,而非字符串字面量
  • using 指令位于最深层作用域
  • 没有内联注释(代码能自我说明)

🟡 现代 C# 模式:

  • 使用 LINQ,而非手动循环
  • 简单成员使用表达式体
  • 使用空合并运算符
  • 类型检查使用模式匹配
  • 适当使用现代 C# 特性

🟢 Unity 架构:

  • 正确使用 VContainer/TheOne.DI
  • 正确使用 SignalBus/Publisher-Subscriber
  • 仅通过控制器访问数据
  • 在 Dispose 中取消订阅所有信号
  • 在构造函数上使用 [Preserve] 或 [Inject] 特性

🟢 Unity 特定要求:

  • 在 Dispose 中卸载已加载的资源
  • 不在 Update/运行时循环中使用 Find/GetComponent
  • 使用 TryGetComponent,而非 GetComponent + null 检查
  • 生命周期方法的顺序正确

🔵 性能:

  • Update/FixedUpdate 中没有分配
  • 避免在热点路径中使用 LINQ
  • 未修改集合时使用 .ToArray(),而非 .ToList()

应避免的常见错误

❌ 不要:
  1. 忽略可空性警告 → 启用 #nullable 并修复所有警告
  2. 记录错误而不是抛出异常 → 遇到错误时抛出异常
  3. 在运行时代码中使用 Debug.Log → 使用 TheOne.Logging.ILogger(Debug.Log 仅用于编辑器)
  4. 为日志添加条件保护 → ILogger 会在内部处理 #if
  5. 手动添加日志前缀 → ILogger 会自动处理 [prefix]
  6. 在构造函数中记录日志 → 切勿在构造函数中记录日志(保持快速且无副作用)
  7. 使用 logger?.Method() → 使用 logger.Method()(DI 保证其不为 null)
  8. 添加冗余日志 → 仅保留必要的日志
  9. 省略访问修饰符 → 始终使用限制性最强的访问修饰符(默认为 private)
  10. 硬编码字符串 → 使用 nameof() 表示属性名和参数名
  11. 让字段保持可变 → 尽可能使用 readonly/const
  12. 使用 Zenject → 使用 VContainer
  13. 直接使用 MessagePipe → 使用 SignalBus
  14. 直接访问数据模型 → 使用 Controllers
  15. 忘记取消订阅信号 → 实现 IDisposable
  16. 添加行内注释 → 改用描述性名称
✅ 应该:
  1. 启用可空引用类型(#nullable enable)
  2. 遇到错误时抛出异常(绝不记录错误日志)
  3. 在运行时代码中使用 TheOne.Logging.ILogger(不加条件保护、不加前缀、不在构造函数中记录日志)
  4. 直接使用 logger.Method()(不使用空条件运算符,DI 保证其不为 null)
  5. Debug.Log 仅用于编辑器(#if UNITY_EDITOR)
  6. 使用限制性最强的修饰符(默认为 private)
  7. 使用描述性名称(不添加行内注释)
  8. 使用 nameof() 表示字符串字面量
  9. 对不可变字段使用 readonly/const
  10. 使用 VContainer 或 TheOne.DI 进行依赖注入
  11. 对所有事件使用 SignalBus 或 Publisher/Subscriber
  12. 使用 Controllers 访问所有数据
  13. 始终实现 IDisposable 并取消订阅
  14. 添加 [Preserve] 或 [Inject],防止代码剥离
  15. 使用 LINQ 进行集合操作

审查严重程度

🔴 严重(必须修复)
  • 未修复可空性警告 — 启用 #nullable 并修复所有警告
  • 记录错误而不是抛出异常 — 遇到错误时应抛出异常,而不是记录日志
  • 在运行时代码中使用 Debug.Log — 必须使用 TheOne.Logging.ILogger(Debug.Log 仅用于编辑器)
  • 对日志使用条件保护 — ILogger 会在内部处理 #if,请移除条件保护
  • 手动添加日志前缀 — ILogger 会自动处理 [prefix],请移除前缀
  • 在构造函数中记录日志 — 切勿在构造函数中记录日志(保持快速且无副作用)
  • 对 logger 使用空条件运算符 — 使用 logger.Method(),而不是 logger?.Method()
  • 缺少访问修饰符 — 所有成员都必须显式声明修饰符
  • 忽略编译器警告 — 对警告零容忍
  • 行内注释 — 改用描述性名称
  • 使用 Zenject 而不是 VContainer
  • 使用 MessagePipe 而不是 SignalBus
  • 直接访问数据(未使用 Controllers)
  • 内存泄漏(未取消订阅)
  • 未实现 IDisposable
🟡 重要(应该修复)
  • 缺少 readonly/const — 尽可能将字段声明为 readonly/const
  • 硬编码字符串 — 使用 nameof() 表示属性名和参数名
  • using 指令未置于最内层作用域 — 尽可能在方法级别使用 using
  • 冗余且不必要的日志 — 仅保留必要的日志
  • 使用冗长代码而不是 LINQ
  • 缺少 [Preserve] 或 [Inject] 特性
  • 热路径中的性能问题
  • 业务逻辑缺少单元测试
  • 公共 API 缺少 XML 文档
🟢 可改进(建议)
  • 可以使用表达式主体
  • 可以使用空条件运算符
  • 可以使用模式匹配
  • 可以改进命名
  • 可以使用现代 C# 特性简化代码

详细参考

C# 编码规范
Unity 架构
代码审查

总结

此技能为 TheOne Studio 提供全面的 Unity 开发规范:

  • C# 卓越实践:现代、简洁、专业的 C# 代码
  • Unity 架构:VContainer+SignalBus 或 TheOne.DI+Publisher 模式
  • 代码质量:严格执行质量、规范和性能规则
  • 代码审查:用于拉取请求审查的完整清单

使用上方的快速参考指南,找到所需的特定模式。

评论

支持 Markdown