琼港计划——Beta冲刺代码规范

琼港计划团队账号 2025-11-24 22:27:03
这个作业属于哪个课程2501_CS_SE_FZU
这个作业要求在哪里团队作业—Beta冲刺
这个作业的目标相比alpha冲刺,构建更加系统,完整的代码规范
其他参考文献命名准则(微软),代码风格(谷歌),《编写可读代码的艺术》,《Effective C#》,《构建之法(第三版)》

目录

目录

  • 目录
  • C#/Unity 代码规范手册
  • 基本准则
  • 1. Unity编程规范
  • 1.1 Unity命名风格
  • 1.1.1 命名基本规则
  • 1.1.2 Unity特定命名
  • 1.2 代码格式
  • 1.2.1 大括号
  • 1.2.2 缩进
  • 1.3 Unity特定编程规范
  • 1.3.1 组件访问
  • 1.3.2 MonoBehaviour生命周期
  • 1.4 注释规范
  • 1.4.1 注释基本原则
  • 1.4.2 文档注释
  • 1.4.3 Inspector注释
  • 1.4.4 类注释规范
  • 1.4.5 方法注释规范
  • 1.4.6 变更记录规范
  • 1.4.7 变量与字段注释
  • 1.4.8 逻辑注释
  • 1.4.9 排版与语言
  • 2. Unity架构规范
  • 2.1 管理器模式
  • 2.1.1 单例管理器
  • 2.1.2 事件系统
  • 2.2 性能优化
  • 2.2.1 内存管理
  • 2.2.2 协程管理
  • 3. C# 编程规范
  • 3.1 C#命名规范
  • 3.1.1 标识符有效性
  • 3.1.2 命名约定
  • 3.2 C#编程规范
  • 3.2.1 字符串与文本处理
  • 3.2.2 构造函数与初始化
  • 3.2.3 数组与集合初始化
  • 3.2.4 委托与 lambda
  • 3.2.5 异常处理与 using
  • 3.2.6 布尔运算符 && 与 ||
  • 3.2.7 new 运算符与对象初始化
  • 3.2.8 事件处理与 lambda
  • 3.2.9 静态成员访问
  • 3.2.10 LINQ 查询
  • 3.2.11 隐式类型(var)使用规则
  • 3.2.12 文件作用域命名空间与 using 指令位置
  • 3.3 样式、注释与布局约定
  • 3.3.1 样式指南
  • 3.3.2 注释样式
  • 4. 工程结构规范
  • 4.1 目录结构
  • 4.1.1 资源组织
  • 4.1.2 命名空间
  • 4.2 Git/SVN提交规范
  • 5. 资源管理规范
  • 5.1 资源加载
  • 5.2 序列化配置
  • 5.3 确保资源访问安全
  • 5.3.1 禁用技术清单
  • 5.3.2 安全边界建议
  • 5.3 确保资源访问安全
  • 5.3.1 禁用技术清单
  • 5.3.2 安全边界建议
  • 6. 测试与调试
  • 6.1 调试规范
  • 6.2 单元测试
  • 附:开发最佳实践检查清单
  • Unity 开发最佳实践检查清单

C#/Unity 代码规范手册

基本准则

  • 尽可能利用Unity 新式语言功能和 C# 版本。
  • 避免过时的语言构造。
  • 只捕获可以正确处理的异常;避免捕获一般异常。
  • 使用特定的异常类型提供有意义的错误消息。
  • 将异步编程与异步和等待用于 I/O 绑定操作。
  • 请谨慎处理死锁.
  • 对数据类型而不是运行时类型使用语言关键字。 例如,使用 string 而不是 System.String,或使用 int 而不是 System.Int32。 此建议包括使用类型 nint 和 nuint。
  • 使用 int 而不是无符号类型。 int 的使用在整个 C# 中很常见,并且当你使用 int 时,更易于与其他库交互。 特定于无符号数据类型的文档例外。
  • 仅当可以从表达式推断类型时使用 var。
  • 以简洁明晰的方式编写代码。
  • 避免过于复杂和费解的代码逻辑。

    1. Unity编程规范

1.1 Unity命名风格

1.1.1 命名基本规则

【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。

【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。

【强制】类名使用 UpperCamelCase 风格,必须遵从帕斯卡命名法。
正例:PlayerController, GameManager, UIManager

【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰命名法。
正例:playerHealth, MoveCharacter(), currentScore

【强制】常量命名全部大写,单词间用下划线隔开。
正例:MAX_HEALTH, DEFAULT_GRAVITY

1.1.2 Unity特定命名

【强制】Unity组件的私有字段使用驼峰命名法,建议添加SerializeField特性。
正例:

[SerializeField] private int playerHealth;
[SerializeField] private GameObject projectilePrefab;

【建议】布尔类型的变量命名应使用is、has、can等前缀。
正例:isAlive, hasWeapon, canJump

【强制】事件和委托使用适当的后缀。
正例:OnPlayerDeath, OnScoreChanged

1.2 代码格式

1.2.1 大括号

【强制】使用Allman风格大括号,即左大括号换行。

【强制】即使只有一行代码,也要使用大括号。
正例:

if (isAlive)
{
    Move();
}

反例:

if (isAlive)
    Move();

1.2.2 缩进

【强制】采用 4 个空格缩进,禁止使用 Tab 字符。

【强制】单行字符数限制不超过 120 个,超出需要换行。

1.3 Unity特定编程规范

1.3.1 组件访问

【强制】在Awake或Start中缓存频繁访问的组件引用,避免在Update中使用GetComponent。
正例:

private Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

1.3.2 MonoBehaviour生命周期

【强制】理解并正确使用Unity的生命周期方法:

  • Awake:初始化组件引用
  • Start:初始化游戏逻辑
  • Update:每帧更新
  • FixedUpdate:物理更新
  • OnDestroy:清理资源

1.4 注释规范

1.4.1 注释基本原则

【强制】所有的方法和函数都应该以描述这段代码的功能的一段简明注释方法是干什么。描述不应包括它是怎么做的等具体细节,避免注释随代码变更而过时。

【强制】注释的内容要清楚、明了,含义准确,防止注释二义性。修改代码同时修改相应的注释,不再有用的注释要删除。

【强制】不允许在一行代码或表达式的中间插入注释。

【建议】源程序注释量尽量在30%以上。建议以一个系统内部模块作为单位进行检查。

1.4.2 文档注释

【强制】公共方法和类必须使用XML文档注释。
正例:

/// <summary>
/// 处理玩家受伤逻辑
/// </summary>
/// <param name="damage">受到的伤害值</param>
public void TakeDamage(int damage)
{
    // 实现
}

1.4.3 Inspector注释

【建议】使用特性为Inspector字段添加说明。
正例:

[Header("玩家属性")]
[Tooltip("玩家的生命值")]
[SerializeField] private int health = 100;

1.4.4 类注释规范

【强制】每个类开头必须要有以下注释,位于 using 代码块之下。
正例:

using UnityEngine;

/// <summary>
/// 一句话简述
/// 作用:(对此类的详细描述)
/// 作者:(创建者的中文名字)
/// 编写日期:(模块创建日期,格式:YYYY-MM-DD)
/// 适用Unity版本:(2021.3.27f1c2 - 2022.3.3f1c1)
/// 脚本适用平台:(Android iOS)
/// 脚本使用注意事项:(例如:序列帧文件名称必须从0开始计数,即 图片名_0000 类似命名)
/// TODO:(还需要完成的功能)
/// </summary>
public class PlayerManager : MonoBehaviour
{
}

1.4.5 方法注释规范

【强制】每个方法开头必须要有以下XML格式注释。
正例:

/// <summary>
/// 方法名称
/// 作用:(对这个方法的作用进行简单描述,包括所有参数的简单描述)
/// 作者:(方法创建者的中文名字)
/// 编写日期:(方法创建日期,格式:YYYY-MM-DD)
/// </summary>
/// <param name="_str1">参数_str1的详细说明</param>
/// <param name="_str2">参数_str2的详细说明</param>
/// <returns>返回值说明</returns>
/// <exception>异常说明</exception>
/// <remarks> 
/// 该方法详细文字说明
/// </remarks>
/// <example>
/// <code>调用此方法的代码示例</code>
/// </example>
public int TestClass(string _str1, string _str2)
{
    return 0;
}

1.4.6 变更记录规范

【强制】其他人对代码做出修改后,要在“作者”一行中加入自己的名字。

【建议】在“作用”描述中,使用以下标记记录变更:

@since YYYY-MM-DD:表示从哪个日期开始,做出了什么样的修改或新功能。
@deprecated YYYY-MM-DD:表示从哪个日期开始,弃用了哪些功能。
@see 类名/方法名:表示相关的类或者方法。
@Override:表示重载父类的方法,并对重载进行文字说明。
正例:

/// <summary>
/// 方法名称
/// 作用:@since 2023-05-15 添加了对AB包进行二次加密和解密的功能
///       @deprecated 2023-05-17 弃用了之前过于简单的加密方式
///       @Override 对ResetCharacter方法进行的重载,这里是重置新添加的中立生物的状态
/// 作者:(方法创建者的中文名字)
/// 编写日期:(方法创建日期,格式:YYYY-MM-DD)
/// </summary>

1.4.7 变量与字段注释

【强制】类和方法中声明的变量、属性、字段,其上一行均要有 // 形式的注释说明。
正例:

// 说明这个变量的具体作用
[SerializeField] private string playerName = "abc";

1.4.8 逻辑注释

【强制】在代码的功能、意图层次上进行注释,提供有用、额外的信息,而不是简单的代码翻译。

【强制】对关键变量的定义和分支语句(条件分支、循环语句等)必须编写注释。这些语句往往是程序实现某一特定功能的关键。

正例:

// 错误示例:如果 receiveFlag 为真
// 正确示例:如果从连结收到消息 
if (receiveFlag)
{
    // ...
}

1.4.9 排版与语言

【建议】注释应考虑程序易读及外观排版的因素。

【建议】使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。中文注释中需使用中文标点。

【建议】方法和类描述的第一句话尽量使用简洁明了的话概括一下功能,然后加以句号。

2. Unity架构规范

2.1 管理器模式

2.1.1 单例管理器

【建议】对于全局管理器使用单例模式,但要谨慎使用。
正例:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

2.1.2 事件系统

【建议】使用基于委托的事件系统进行组件间通信,减少耦合。
正例:

public class EventManager : MonoBehaviour
{
    public static event Action<int> OnScoreChanged;
    
    public static void RaiseScoreChanged(int newScore)
    {
        OnScoreChanged?.Invoke(newScore);
    }
}

2.2 性能优化

2.2.1 内存管理

【强制】避免在Update中实例化对象,使用对象池。
正例:

public class ProjectilePool : MonoBehaviour
{
    [SerializeField] private GameObject projectilePrefab;
    private Queue<GameObject> projectiles = new Queue<GameObject>();
    
    public GameObject GetProjectile()
    {
        if (projectiles.Count > 0)
        {
            return projectiles.Dequeue();
        }
        return Instantiate(projectilePrefab);
    }
}

2.2.2 协程管理

【强制】妥善管理协程的生命周期,避免内存泄漏。
正例:

private Coroutine damageCoroutine;

private void StartDamageEffect()
{
    if (damageCoroutine != null)
    {
        StopCoroutine(damageCoroutine);
    }
    damageCoroutine = StartCoroutine(DamageEffectRoutine());
}

3. C# 编程规范

3.1 C#命名规范

3.1.1 标识符有效性

【强制】标识符必须以字母或下划线(_)开头;可以包含 Unicode 字母、十进制数字、连接字符、组合字符或格式字符;可使用 @ 前缀声明逐字标识符(用于与关键字同名的标识符)。
示例:

// 合法标识符
int _count;
string name123;
var @class = "关键字作为标识符"; // 声明名为 class 的标识符

【重要】语言规范只允许特定 Unicode 类别(字母、数字、连接、组合、格式);其他字符会被替换为下划线,可能影响某些 Unicode 字符的使用。
【强制】标识符不应包含两个连续下划线(__),这是编译器保留的模式。
反例:

// 不应使用
int __generatedId; // 避免:与编译器生成标识符冲突

3.1.2 命名约定

【建议】对类型(class、struct、enum、delegate)、命名空间和所有对外可见成员使用 PascalCase(UpperCamelCase)。接口以大写 I 前缀。
示例:

public class PlayerController { }
public interface IWorkerQueue { }
public struct ValueCoordinate { }
public delegate void Notify(string message);
namespace CompanyName.GameName.Gameplay { }

【建议】方法、属性与事件使用 PascalCase。
示例:

public void StartGame() { }
public int MaxPlayers { get; set; }
public event Action OnPlayerDeath;

【强制】方法参数和局部变量使用 camelCase(lowerCamelCase)。
示例:

public void ProcessData(int itemCount, bool isActive)
{
    int currentIndex = 0;
}

【强制】私有实例字段使用下划线前缀 + 驼峰(camelCase)。对于静态字段可使用 s 前缀;线程静态字段可使用 t_ 前缀(项目可选约定)。
示例:

private IWorkerQueue _workerQueue;
private static TimeSpan s_cachedTimeout;
[ThreadStatic] private static int t_threadId;

【强制】规定常量使用全大写与下划线分隔
示例:

public const int MAX_HEALTH = 100;
private const string DEFAULT_NAME = "Player";

【建议】泛型类型参数使用描述性名称,单字母名称仅在自我说明时允许(常用 T 或 TValue 等)。对于描述性名称,前缀使用 T
示例:

public interface ISessionChannel<TSession> { TSession Session { get; } }
public delegate TOutput Converter<TInput, TOutput>(TInput input);
public class Cache<TItem> { }

【强制】对于 class 和 struct 主构造函数参数使用 camelCase;对于 record 主构造参数使用 PascalCase(因为会成为公共属性)。
示例:

public class DataService(IWorkerQueue workerQueue, ILogger logger) { }
public struct Point(double x, double y) { }

【强制】使用 EditorConfig、代码样式规则或 IDE 的命名规则来在团队中强制命名约定。

3.2 C#编程规范

3.2.1 字符串与文本处理

【建议】使用字符串内插(interpolation)连接短字符串以提高可读性,而不是使用连接运算符或 String.Format。
正例:

string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";

【强制】在循环中或处理大量文本时,使用 System.Text.StringBuilder 以避免大量短字符串拼接带来的性能开销。
正例:

var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
    manyPhrases.Append(phrase);
}
// Console.WriteLine(manyPhrases.ToString());

【建议】优先使用原始字符串字面量(raw string literal)来表达跨行或包含大量转义字符的文本。
正例:

var message = """
    This is a long message that spans across multiple lines.
    It uses raw string literals. This means we can 
    also include characters like \n and \t without escaping them.
    """;

【建议】使用基于表达式的字符串内插,而不是位置字符串内插(避免使用 {0}、{1} 等)。
正例:

Console.WriteLine($"{student.Last} Score: {student.score}");

3.2.2 构造函数与初始化

【强制】记录类型(record)的主构造函数参数使用 PascalCase(因为会成为公共属性)。
正例:

public record Person(string FirstName, string LastName);

【强制】类和结构体的主构造函数参数使用 camelCase。
正例:

public class DataService(IWorkerQueue workerQueue, ILogger logger) { }
public struct Point(double x, double y) { }

【建议】优先使用 required 属性而非过多构造函数来强制初始化属性值(适用于 .NET 版本支持 required 的情况)。
正例:

public class LabelledContainer<T>(string label)
{
    public string Label { get; } = label;
    public required T Contents { get; init; }
}

3.2.3 数组与集合初始化

【建议】使用集合表达式或集合初始化器来初始化集合,使意图清晰。
正例:

string[] vowels = [ "a", "e", "i", "o", "u" ];
// 或
var list = new List<int> { 1, 2, 3, 4 };

3.2.4 委托与 lambda

【建议】优先使用泛型委托 Func<> 和 Action<>,并使用 lambda 表达式或方法组简洁创建实例。
正例:

Action<string> actionExample1 = x => Console.WriteLine($"x is: {x}");
Func<string, int> funcExample1 = x => Convert.ToInt32(x);

actionExample1("string for x");
Console.WriteLine($"The value is {funcExample1("1")}");

【建议】仅在确有必要时才定义自定义 delegate 类型;使用方法组语法实例化委托更简洁。
正例:

public delegate void Del(string message);

public static void DelMethod(string str)
{
    Console.WriteLine($"DelMethod argument: {str}");
}

Del exampleDel2 = DelMethod; // 方法组简化语法
exampleDel2("Hey");

3.2.5 异常处理与 using

【强制】只捕获并处理你能正确处理的特定异常类型,避免捕获 System.Exception。
正例:

static double ComputeDistance(double x1, double y1, double x2, double y2)
{
    try
    {
        return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }
    catch (System.ArithmeticException ex)
    {
        Console.WriteLine($"Arithmetic overflow or underflow: {ex}");
        throw;
    }
}

【强制】如果 finally 块唯一用途是调用 Dispose,请改用 using 语句(含新的 using 声明语法)。
正例:

using (Font arial = new Font("Arial", 10.0f))
{
    byte charset2 = arial.GdiCharSet;
}

// 或使用不带大括号的新语法(简洁,作用域为当前块):
using Font normalStyle = new Font("Arial", 10.0f);
byte charset3 = normalStyle.GdiCharSet;

3.2.6 布尔运算符 && 与 ||

【强制】在逻辑比较中使用短路运算符 && 和 ||,避免使用 & 和 |(除非确实需要按位或总是求值的行为)。
正例:

if ((divisor != 0) && (dividend / divisor) is var result)
{
    Console.WriteLine($"Quotient: {result}");
}
else
{
    Console.WriteLine("Attempted division by 0 ends up here.");
}

3.2.7 new 运算符与对象初始化

【建议】当变量声明的类型与构造对象类型一致时,使用简洁的 new() 语法或 var + new。
正例:

var firstExample = new ExampleClass();
ExampleClass instance2 = new();
ExampleClass secondExample = new ExampleClass();

【建议】优先使用对象初始化器来简化属性赋值。
正例:

var thirdExample = new ExampleClass
{
    Name = "Desktop",
    ID = 37414,
    Location = "Redmond",
    Age = 2.3
};

3.2.8 事件处理与 lambda

【建议】使用 lambda 表达式定义短小且无需注销的事件处理器;对于需要后续注销的处理器,使用具名方法以便移除。
正例(无需移除):

this.Click += (s, e) =>
{
    MessageBox.Show(((MouseEventArgs)e).Location.ToString());
};

3.2.9 静态成员访问

【强制】通过类型名调用 static 成员(ClassName.StaticMember),不要使用派生类名来限定基类中定义的静态成员。这样能保持可读性并避免未来潜在问题。

3.2.10 LINQ 查询

【建议】为查询变量使用有意义的名称;为匿名类型属性使用 PascalCase,并在有歧义时重命名属性以提高可读性。
正例:

var seattleCustomers = from customer in Customers
                       where customer.City == "Seattle"
                       select customer.Name;

var localDistributors2 =
    from customer in Customers
    join distributor in Distributors on customer.City equals distributor.City
    select new { CustomerName = customer.Name, DistributorName = distributor.Name };

【建议】在查询和范围变量中使用隐式类型(var),尤其是当结果为匿名类型或复杂泛型时。

3.2.11 隐式类型(var)使用规则

【强制】当变量右侧类型明显时使用 var(例如 new、字面量或显式转换);当类型不明显时使用显式类型。
正例:

var message = "This is clearly a string.";
var currentTemperature = 27;
var phrase = "lalala";
for (var i = 0; i < 10000; i++) { ... }

反例(类型不明显时不要使用 var):

var currentMaximum = ExampleClass.ResultSoFar(); // 不推荐,类型不明确

【强制】在 foreach 循环中显式声明循环变量类型,除非集合元素类型非常明显。
正例:

foreach (char ch in laugh)
{
    // ...
}

3.2.12 文件作用域命名空间与 using 指令位置

【建议】多数代码文件应使用文件作用域命名空间声明以减少嵌套缩进。
正例:

namespace MySampleCode;

【强制】将 using 指令放在命名空间声明之外,避免引入上下文相关的名称解析问题。
正例:

using Azure;

namespace CoolStuff.AwesomeFeature
{
    public class Awesome
    {
        public void Stuff()
        {
            WaitUntil wait = WaitUntil.Completed;
        }
    }
}

3.3 样式、注释与布局约定

3.3.1 样式指南

【强制】使用四个空格缩进。 不要使用选项卡(Tab)。

【建议】一致地对齐代码以提高可读性。

【建议】将行限制为 65 个字符,以增强文档上的代码可读性,尤其是在移动屏幕上。通过将长语句分解为多行来提高清晰度和用户体验。

【强制】对大括号使用“Allman”样式:左和右大括号另起一行。 大括号与当前缩进级别对齐。
正例:

if (isActive)
{
    ProcessData();
}

【建议】如有必要,应在二元运算符之前换行。
正例:

var totalScore = currentScore
    + bonusPoints
    + levelMultiplier;

3.3.2 注释样式

【建议】使用单行注释(//)以进行简要说明。避免使用多行注释(/* */)来进行较长的解释。

【强制】若要描述方法、类、字段和所有公共成员,请使用 XML 注释。

【强制】将注释放在单独的行上,而非代码行的末尾。

【强制】在注释分隔符 (//) 与注释文本之间插入一个空格。

【建议】注释文本首字母大写,并以句点结束(针对英文注释)。
正例:

// The following declaration creates a query. It does not run
// the query.
var query = from item in collection select item;

3.3.3 布局约定
【建议】使用默认的代码编辑器设置(智能缩进、4 字符缩进、制表符保存为空格)。

【强制】每行只写一条语句。
正例:

// 正确
count++;
name = "Unity";

// 错误
count++; name = "Unity";

【强制】每行只写一个声明。
正例:

// 正确
int x;
int y;

// 错误
int x, y;

【强制】如果连续行未自动缩进,请将它们缩进一个制表符位(四个空格)。

【建议】在方法定义与属性定义之间添加至少一个空白行。

【建议】使用括号突出表达式中的子句,除非是解释运算符或表达式优先级的情况。
正例:

if ((startX > endX) && (startXif ((startX > endX) && (startX > previousX))))
{
// Take appropriate action.
}

4. 工程结构规范

4.1 目录结构

4.1.1 资源组织

【强制】按照功能模块组织项目结构。
正例:

Assets/
├── Scripts/
│   ├── Core/           # 核心系统
│   ├── Gameplay/       # 游戏逻辑
│   ├── UI/            # 用户界面
│   ├── Utilities/      # 工具类
│   └── Managers/       # 管理器
├── Prefabs/
├── Scenes/
├── Art/
└── Audio/

4.1.2 命名空间

【建议】使用命名空间组织代码结构。
正例:

namespace CompanyName.GameName.Gameplay
{
    public class PlayerController : MonoBehaviour
    {
        // 实现
    }
}

4.2 Git/SVN提交规范

[建议]
提交模板

[类型] 类型关键字
[标题] 此次提交是进行哪些改动简述
[描述] 对此次提交进行详细的文字描述
[Bug修复情况] 此行为可选填,下面会说明如何填写

提交类型,在提交更改时,第一行要写的关键字,可以较快的辨别该提交是那种类型的

提交类型可以有多个,比如修复BUG是修改了UI模型,那么[类型]就是fix UI,两个类型之间用英文半角空格进行间隔
BUG修复情况说明,如果此次提交为修复BUG,要写明之前的BUG是什么样子的,例如网络访问错误还是人物操作抖动等,如果是修改issue的话,要引用该issue

[强制]在每次提交后与组内成员通知,并做好记录

5. 资源管理规范

5.1 资源加载

【建议】使用Addressable Assets系统进行资源管理,避免Resources文件夹的滥用。

【强制】在合适的时机卸载不再使用的资源,避免内存泄漏。

5.2 序列化配置

【建议】使用ScriptableObject存储游戏配置数据。
正例:

[CreateAssetMenu(fileName = "GameSettings", menuName = "Game/Game Settings")]
public class GameSettings : ScriptableObject
{
    public float gameTime = 60f;
    public int maxPlayers = 4;
}

5.3 确保资源访问安全

在设计和编写代码时,需要保护和限制代码对资源的访问权限,尤其是在使用或调用未知来源的代码时。

5.3.1 禁用技术清单

【强制】请勿使用代码访问安全性(CAS)。

【强制】请勿使用部分受信任的代码。

【强制】请勿使用 AllowPartiallyTrustedCaller 属性(APTCA)。

【强制】请勿使用 .NET 远程处理。

【强制】请勿使用分布式组件对象模型(DCOM)。

【强制】请勿使用二进制格式化程序。

5.3.2 安全边界建议

【建议】不要加载和执行未知来源的代码,除非采取了替代安全措施。
未来不支持将代码访问安全性和安全透明代码用作部分信任代码的安全边界。

5.3 确保资源访问安全

在设计和编写代码时,需要保护和限制代码对资源的访问权限,尤其是在使用或调用未知来源的代码时。

5.3.1 禁用技术清单

【强制】请勿使用代码访问安全性(CAS)。

【强制】请勿使用部分受信任的代码。

【强制】请勿使用 AllowPartiallyTrustedCaller 属性(APTCA)。

【强制】请勿使用 .NET 远程处理。

【强制】请勿使用分布式组件对象模型(DCOM)。

【强制】请勿使用二进制格式化程序。

5.3.2 安全边界建议

【建议】不要加载和执行未知来源的代码,除非采取了替代安全措施。
未来不支持将代码访问安全性和安全透明代码用作部分信任代码的安全边界。

【建议】使用以下替代安全措施:

  • 虚拟化
  • AppContainers
  • 操作系统(OS)用户和权限
  • Hyper-V 容器

6. 测试与调试

6.1 调试规范

【强制】使用适当的日志级别:

  • Debug.Log(): 普通信息
  • Debug.LogWarning(): 警告信息
  • Debug.LogError(): 错误信息

【建议】在发布版本中移除或禁用不必要的日志输出。

6.2 单元测试

【建议】为核心游戏逻辑编写单元测试,使用Unity Test Framework。

附:开发最佳实践检查清单

代码质量与规范

  • 零警告原则:确保编译通过且没有任何警告(Warnings),清理未使用的 using 引用。
  • 命名一致性:类/方法/属性使用 PascalCase,参数/局部变量使用 camelCase,常量使用 UPPER_CASE
  • 类型关键字:使用 C# 语言关键字int, string而非 CLR 类型Int32, String
  • var 的使用:仅在右侧类型显而易见如 new 或显式转换时使用 var,否则显式声明类型。

逻辑与性能

  • 字符串处理:短字符串拼接使用插值 $,循环或大量拼接必须使用 StringBuilder
  • 集合操作:优先使用 LINQ 提高可读性,但在高性能热点路径(Hot Path)中需谨慎评估 GC 开销。
  • 逻辑简化:避免超过3层的深层嵌套,使用卫语句(Guard Clauses)提前返回;使用短路运算符 &&||
  • 异常处理:仅捕获能处理的特定异常,避免捕获通用的 System.Exception;使用 using 语句块自动释放非托管资源。

架构与设计

  • SOLID 原则:检查代码是否符合单一职责、开闭原则等面向对象设计原则。
  • 访问控制:默认使用最低权限private,仅在必要时公开public/internal
  • 代码复用:重复代码提取为方法,通用功能提取为工具类或扩展方法。

Unity 开发最佳实践检查清单

架构设计

  • 组件设计:使用组件模式而非继承深度层次
  • 解耦通信:通过事件系统解耦组件
  • 单例使用:合理使用单例模式
  • 静态成员:避免静态变量的滥用

性能优化

  • Update优化:避免在Update中调用昂贵操作
  • 异步逻辑:合理使用协程替代Invoke
  • 对象池化:对于频繁创建和销毁的对象如特效,必须使用对象池,避免在 UpdateInstantiatenew 对象。
  • 物理更新:优化物理计算和碰撞检测,物理相关的逻辑(如刚体操作)必须放在 FixedUpdate 中。
  • 协程管理:妥善管理协程生命周期,避免开启无法停止的协程导致内存泄漏;简单延时可考虑 UniTaskInvoke

内存管理

  • 事件清理:及时取消注册事件
  • 协程生命周期:妥善管理协程生命周期
  • 内存分配:避免不必要的对象实例化
  • 性能分析:定期进行内存分析

生命周期与组件

  • 缓存引用:在 AwakeStart 中缓存组件引用GetComponent,严禁在 Update 中获取组件或查找对象Find
  • 字段封装:Inspector 面板变量使用 [SerializeField] private,避免直接使用 public 破坏封装性。
  • 清理工作:在 OnDestroy 中移除事件监听、停止协程并清理非托管资源。

架构与资源

  • 解耦通信:使用 C# 事件Action, Func或消息中心进行组件间通信,减少强引用耦合。
  • 资源加载:避免滥用 Resources 文件夹,建议使用 Addressables 或 AssetBundle;确保及时卸载未引用资源。
  • 调试日志:使用 Debug.Log 时注意级别,确保发布版本(Release)中剥离或禁用不必要的日志输出。
  • 配置数据:静态配置数据优先使用 ScriptableObject 存储,而非硬编码在脚本中。
...全文
25 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

103

社区成员

发帖
与我相关
我的任务
社区描述
2501_CS_SE_FZU
软件工程 高校
社区管理员
  • FZU_SE_LQF
  • 木村修
  • 心态773
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧