编码规范
Version 2.4.4 by win for Unity
全局修饰符顺序
在本规范下,修饰符优先级从高到低排序为:
-
public
、internal
、protected internal
、protected
、private protected
、private
-
static
、new
、sealed
、override
、const
-
readonly
、event
、async
优先级越高,则书写时越应位于左侧。
public static readonly int number;
static public readonly int number;
全局标识符约定
在本规范下,所有遵守此约定的标识符应使用英语书写,允许使用缩写,不允许简写。若某个单词作为缩写(如UI,ID,AI,GUID)使用,那么该单词必须全部大写或全部小写。
尽管本规范没有规定任何可使用的缩写单词,但当开发人员使用缩写时,该缩写单词必须是普遍使用并被认可的,如将 Callback 缩写为 CB 是错误的,而将 Artificial intelligence 缩写为 AI 则是正确的。
字段/属性约定
标识符约定
在本规范下,字段和属性的标识符使用小驼峰法 (lowerCamelCase) 命名,在此基础上,有下列特殊约定:
Boolean 类型约定
所有 bool 类型的字段/属性严禁以 is 为前缀。
public bool isOpen;
public bool opened;
函数指针(委托和事件)约定
所有函数指针类型的字段/属性必须以单词 on 为前缀。
public event Action onOpen;
数据结构约定
数据结构类型的字段/属性有以下约定:
- 数组以单词 Array 或复数字母 s 作为后缀;
- 字典以单词 Dictionary 作为后缀;
- 列表以单词 List 作为后缀;
其余数据结构或者自定义数据结构,均以其类名作为后缀;
接口类型约定
如果类型显式被指定为接口,则标识符可以省略前缀 I。
public IData data;
public IData data2 { get; private set; }
属性操作数约定
如果某一字段只是属性的操作数,并且无其它任何含义,那么该字段以下划线作为前缀,且名称与属性名一致,如:
public float time
{
get => _time;
set { if (value > 0) _time = value; }
}
private float _time;
属性使用约定
对于所有可改写成Lambda表达式主体的访问器,必须改写; 严禁使用只对一个变量进行只读只写操作的属性。
public float time { get { return _time; } set { _time = value; } }
private float _time;
以上代码必须改为自动属性:
public float time { get; set; }
但如果在属性中对字段进行操作,那么以下代码是允许的:
public float time
{
get => _time;
set { if (value > 0) _time = value; }
}
private float _time;
字段使用约定
不允许任何形式的多字段声明,以下代码是不允许的:
public float a, b, c;
类(class)约定
标识符约定
类标识符在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名,且有以下特殊约定:
- 如果类的主要功能是提供对某个类型的扩展,则类名应为 <扩展对象的类名>Extension (如 TransformExtension);
- 如果类的主要功能是提供工具函数且为 static,则类名应为 <功能>Utility (如 DataUtility);
修饰符约定
- 密封约定:若类不进行任何派生,则必须加上 sealed 修饰符。
- 访问范围约定:若类不对外公开,则必须使用 internal 访问修饰符。
特性(Attribute)约定
特性标识符在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名,并以Attribute作为后缀:
特性应用约定
在本规范下,特性只可以置于声明实体的上方,当有多个特性时,必须放置在同一个方括号内。
public class Data
{
[System.NonSerialized] public string name;
}
public class Data
{
[UnityEngine.Space]
[System.NonSerialized]
public string name;
}
public class Data
{
[System.NonSerialized]
public string name;
}
public class Data
{
[System.NonSerialized, UnityEngine.Space]
public string name;
}
结构(struct)约定
标识符约定
结构标识符在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名。
接口(interface)约定
标识符约定
接口标识符在遵守 全局标识符约定 的情况下使用微软规范命名: 即先以大驼峰法 (Upper Camel Case) 命名,再使用字母 I 作为标识符前缀。
枚举(enum)约定
标识符约定
枚举标识符在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名。
枚举成员标识符约定
枚举成员标识符在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名。
枚举成员定义约定
在本规范下,枚举成员必须按列定义:
public enum DirectionType
{
Up, Left, Right, Bottom
}
public enum DirectionType
{
Up,
Left,
Right,
Bottom
}
预处理器约定
标识符约定
预处理器符号标识符应使用大写英语书写,允许使用缩写,不允许简写,单词之间必须使用下划线。
#if PLATFORM_WINDOWS
泛型约定
标识符约定
泛型标识符仅使用单个大写的英文字母,且第一个标识符总是使用大写字母 T,之后的标识符可使用除 T 之外的其它大写字母。
方法约定
标识符约定
方法标识符在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名,在此基础上,有以下特殊情况:
回调方法
如果方法仅作为回调方法使用,那么其标识符必须以单词 Callback 作为后缀。
public void MouseDownCallback();
异步方法
如果方法为异步方法,且该方法有对应的非异步方法,那么其标识符必须以单词 Async 作为后缀:
public void LoadResource();
public Task LoadResourceAsync();
特殊方法
如果方法满足以下任意条件,则允许在方法中加入下划线和简写来增加可读性:
- 由代码生成的方法;
- 有大量同名的前缀/后缀;
协程方法(Unity协程函数)
在Unity中的协程函数命名必须以后缀 Coroutine 结尾:
public IEnumerator PlayCoroutine();
虚方法
如果方法作为虚方法并且没有任何语句,则需加上前缀 On:
public virtual OnUpdate();
形参标识符约定
形参均使用小驼峰法 (lowerCamelCase) 命名,在此基础上,有以下特殊情况:
- 扩展方法的扩展形参:必须命名为 self;
- 显式/隐式转换方法:自身参数形参名必须是 self;
变量标识符约定
变量使用小驼峰法 (lowerCamelCase) 命名,如无可读性需要,其名称应总是和其类型名一致。 对于类型被显式指定为接口的变量,其变量名可以省略前缀 I。
PlayerData playerData = GetPlayerData();
IData data = GetData();
若有可能需要辨识的情景,允许自定义变量名,如下例: 玩家和敌人都属于 Unit 的实例,此时可以为它们定义一个唯一标识符来区分:
Unit player = new Unit();
Unit enemy = new Unit();
Boolean 类型变量约定
所有 bool 类型的变量严禁以 is 为前缀。
bool isOpen;
bool opened;
标签标识符
标签在遵守 全局标识符约定 的情况下使用大驼峰法 (Upper Camel Case) 命名。
语句约定
using语句
对于非托管资源的释放必须使用 using 语句或手动释放,严禁使用 using 语句块释放资源。
代码块约定
在本规范下,代码块应该在逻辑无关但代码上下文被关联的情况下使用(如 swith 语句中的 case 块)。原则上不应在其它方式下使用代码块。
换行/新行约定
左大括号换行原则
在本规范下,左大括号换行。
空白行约定
在本规范下,代码结构使用单行分隔,不允许出现连续空白行。
语句换行原则
标签语句必须换行,以下代码第2行是不允许的:
int value = 0;
ContinueAdd: value++;
if (value < 100) goto ContinueAdd;
Debug.Log(value);
其它语句严禁换行,即使语句超出了可见范围。以下代码是不允许的:
int number = 1 + 2 + 3 +
4;
新行原则
在本规范下,如果代码块中的语句只有一条,则不另起新行,如以下代码是不允许的:
if (number < 0)
{
Debug.Log("Error");
}
if (number < 0)
Debug.Log("Error");
if (number < 0) Debug.Log("Error");
while,for,foreach 等流程控制语句和 try-catch-finally 异常处理语句同理。 case 子句同理,此时 break、return 应与 case 子句在同一行,如:
swtich (tokenType)
{
case TokenType.Int: break;
case TokenType.String: break;
}
书写优先级
本规范下的书写优先级指代码结构在文件中所在的行数。优先级越高,结构所在的行数越小,越靠上。
总优先级 | 修饰符优先级 | 方法优先级 |
---|---|---|
using指令 | const | 静态构造函数 |
别名定义 | static readonly | 静态方法 |
using static指令 | static | 构造函数 |
属性 | event | 实例方法 |
字段 | readonly | 抽象方法 |
索引器 | 虚方法 | |
方法 | 覆写方法 | |
接口实现 | ||
显式/隐式转换 | ||
运算符重载 | ||
内部类型定义 |
文件与定义
本规范下,除了内部类型定义,一个文件内只允许定义一个类型。
public class Item
{
public ItemType itemType;
}
public enum ItemType
{
Weapon,
Armor
}
ItemType 应该新建一个文件定义,struct,enum,interface,delegate 等类型同理。
访问修饰符约定
在声明和定义任何类型、字段、属性、方法时,必须 显式声明 访问修饰符。
字面量约定
在本规范下,float 类型的字面量必须跟后缀名 f。
在本规范下,所有浮点数类型的字面量禁止省略 0。
float number = .5f;
匿名方法和Lambda表达式约定
在本规范下,禁止在命名方法中使用Lambda主体定义。
public int Add(int a, int b) => a + b;
本规范禁止使用匿名方法,所有匿名方法必须替换成等价的Lambda表达式,且有以下规定:
参数列表
如果参数列表中只有一个形参,则不使用括号。
(message) => Debug.Log(message);
message => Debug.Log(message);
主体
如果方法只有一句语句,则不使用语句块。
message => { Debug.Log(message); };
message => Debug.Log(message);