写在前面:本文是根据alibaba的Java开发手册以及WPF源码整理的一篇适用于C#的开发规范。
命名风格
- 代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
- 命名空间、类名、方法、属性、事件、枚举、公有静态字段、常量使用UpperCamelCase风格。
- 私有字段、参数名、局部变量使用lowerCamelCase风格,遵从驼峰形式。
- 异常类名使用Exception结尾,测试类名以要测试的类名开头,Test结尾。
- 避免在子父类的成员变量间、不同代码块的局部变量间采用相同的命名。
- 杜绝不规范的缩写,要做到望文生义。使用缩写时要是被普遍接受的缩写。
- 为达到代码自解释的目标,命名时应尽量使用完整的单词组合表达意思。
- 在常量与变量命名时,表示类型的名称放在词尾:
startTime
,workQueue
- 接口类中的方法和属性不要加任何修饰符号,加上有效的注释。
- 接口类加I前缀。
- 枚举类名不要加Enum后缀,枚举成员名称使用UpperCamelCase风格命名。
- 用于事件处理的委托加EventHandler后缀,用于事件处理之外的委托加CallBack后缀。
- 在变量名中使用互补对,如min/max、begin/end、open/close
- 不要在事件声明中使用前缀或者后缀,如应使用Close而不是OnClose。
- 如果变量值仅在一个固定范围内变化,使用enum类型定义:
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
-
用UI组件缩写做UI变量前缀,如:
Label - lbl
TextBox - tbox
TextBlock - tblk
Button - btn
Image - img
Grid - grd
StackPanle - stkpnl
代码格式
-
若大括号内为空,简洁的写成{}即可,大括号中间无需换行和空格;如果非空代码块则左右大括号各占一行。
-
左小括号和字符之间不出现空格,右小括号和字符间也不要出现空格。
-
if/for/while/switch/do等保留字与括号之间必须加空格。
-
任何二目、三目运算符的左右两边都需要加一个空格。
-
采用四个空格缩进,禁止使用tab,可在IDE中设置tab为4个空格。
-
注释的双斜线与注释之间有且只有一个空格。
-
在进行类型强制转换时,右括号与强制转换值之间不需要空格。
-
单行字符数限制不超过120个,超出则换行,换行原则如下:
- 第二行相对第一行缩进4个空格,从第三行开始,不再缩进;
- 运算符与下文一起换行;
- 方法调用的点符号与下文一起换行;
- 方法调用的多个参数换行时,在逗号后换行;
- 括号前不要换行
-
方法参数在定义和传入时,多个参数逗号后必须加空格。
-
单个方法的总行数不超过80行。
-
不需要添加若干个空格使变量的赋值等号与上一行对应位置的等号对齐。
-
不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开以提升可读性。以下情况下使用一个空行:
a. 方法与方法,属性与属性之间;
b. 方法中变量声明与语句之间;
c. 方法中不同逻辑块之间;
d. 方法中的返回语句与其他语句之间;
e. 属性与方法,属性与字段,方法与字段之间; -
任何情形下,不需要插入多个空行进行隔开。
-
一行只做一个声明。
-
建议在变量声明时就对其做初始化。
-
不要使用public的实例字段。
-
每行一个语句。
面向对象
-
所有覆盖的方法,必须加override。
-
外部正在使用的接口,不允许修改方法签名,避免对接口调用产生影响。
-
构造函数中禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。
-
一个类有多个构造方法,或多个同名方法时这些方法应该按顺序放在一起,便于阅读。
-
类内方法定义的顺序:公有 > 保护 > 私有。
-
属性的get、set方法中,不要增加业务逻辑,增加排查问题的难度。
-
慎用对象的Clone方法来拷贝对象,因为是浅拷贝,若想实现深拷贝需覆盖Clone方法。
-
类成员与方法的访问严格控制:
- 如果不允许外部直接通过new来创建对象,构造函数必须是private;
- 工具类不能有public构造方法;
- 类非static字段必须是private;
- 类static如果仅在本类使用,必须是private;
- 类方法如果仅供内部调用,必须是private;
- 类方法只对继承类公开,限制为protected。
-
不要给成员变量加任何前缀,区*部变量与成员变量使用this。
-
类名与文件名保持一致。
-
类型成员的排列顺序:
- 委托、事件声明
- 公共静态、常量字段
- 构造函数,参数越少越靠前
- public方法
- 属性
- protected方法 -> private方法 -> internal方法
- 私有字段
控制语句
- 一个switch中,每个case要么通过continue/break/return等来终止,要么注释说明程序将执行到哪一个case为止。一个switch中,必须包含一个default语句放在最后,即使什么代码也没有。
- 当switch内的变量类型为string且为外部参数时,必须先进行null判断。
- 在if/else/for/while/do语句中必须使用大括号,即使只有一行代码。
- if()...else...嵌套语句不要超过3层,避免代码维护困难。
- 不要在条件判断语句中执行复杂的语句,将复杂的逻辑判断结果赋值给一个有意义的布尔值,以提高可读性。
- 不要在其他表达式中插入赋值语句,赋值语句应该单独成行。
- 循环语句要考虑性能,定义对象、变量、获取数据库链接、不必要的try-catch等尽量移至循环体外处理。
- 尽量避免采用取反逻辑运算符,不易理解。
注释
- 字段、属性、枚举值注释:
/// <summary>
/// ...
/// </summary>
public bool IsActive
{
...
}
- 方法、委托注释:
/// <summary>
/// ...
/// </summary>
/// <param name="">...</param>
/// <returns>...</returns>
/// <remarks>(可选)
/// ...
/// </remarks>
private bool Function(int param)
{
...
}
- 类、接口注释:
/// <summary>
/// ...
/// </summary>
public class ClassName
{
...
}
-
方法内部的单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用//注释,不要使用/**/。
-
所有枚举类型的字段必须要有注释,说明数据项的用途。
-
代码修改的同时,注释也要相应修改。
-
谨慎注释掉代码。在上方注释详细说明,而不是简单的注释掉。如果无用,则删除。
-
好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免过多过滥的注释,否则代码一旦修改,注释的修改负担很大。
-
特殊注释标记,需注明标记人与时间。应及时处理这些标记。如:
- 待办(TODO):(标记人,标记时间,[预计处理时间])表示需要实现但暂未实现的功能;
- 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间])错误代码且不能工作,需及时纠正。
-
右花括号"}"后建议添加注释,以便找到对应的"{"。
-
避免在代码行尾添加注释,仅方法内变量声明或花括号后的注释使用行尾注释。
-
文件注释:
// <copyright file="*.cs" company="Hisense">
// Copyright (c) Hisense. All rights reserved.
// </copyright>
// <author>xxx</author>
// <date>yyyy-mm-dd</date>
// <summary>...</summary>
// <modify>(可选)
// 修改人:
// 修改时间:
// 描述:
// </modify>
异常处理
- 通过预检查的方式规避RuntimeException异常,不应该通过catch来处理,如空指针异常,越界异常等。
- 异常不要用来做流程控制,条件控制。
- 对于catch尽可能区分异常类型,再做对应的异常处理。
- 必须处理异常,否则将其抛给调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
- finally块必须对资源对象、流对象进行关闭,有异常也要做try-catch。
- 不要在finally中做return,否则会丢掉try中的返回点。
- 方法的返回值可以为null,但必须加注释说明什么情况下返回null。
- 应尽全力避免NPE(空指针异常)。
- 避免产生重复的代码,否则后期修改时需要修改多个地方,容易遗漏。