编码规范
May 17, 2021About 6 min
编码规范
文件
文件名字和类名字应该一致
MyClass.cs public class MyClass { … }
布局
1. 避免在一个文件中写多个命名空间或者类
这可以让你代码更具有可读性,让他更容易的被找到根据文件名称
2. 命名空间
// .NET namespaces first
using System;
using System.Collections;
// Then any other namespaces in alphabetical order
using Company.Business;
using Company.Standard;
using Telerik.Ajax;
using Telerik.WebControls;
3.每个类布局顺序
- 内部枚举、结构体、类
- 成员变量和属性
- 构造、初始化、销毁方法
- 公有方法
- 私有方法
缩进
1. 基础为4个空格
// A Hello World! program in C#.
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
}
}
}
2. 一行最多130个字符
当一行放不下了,用下面的规则:
- 在逗号之后换行
- 在操作符之后换行
- 新一行对齐前一行同样的表达式级别
方法调用换行实例:
优质:
LongMethodCall(expr1, expr2,
expr3, expr4, expr5);
劣质:
LongMethodCall(expr1, expr2
,expr3, expr4, expr5);
表达式换行实例:
优质:
var result = a * b / (c - g + f) +
4 * z;
劣质:
var result = a * b / (c - g +
f) + 4 * z;
3. 行末的花括号需要放在新的一行
while (x == y)
{
FirstMethod();
SecondMethod();
}
LastMethod();
4. 必须使用花括号即使不需要
即使只有一行的 if
判断句,也需要添加。
if (x == y)
{
DoSomething();
}
空格
规则:
- 关键字后有一个空格:
if,while
for
循环的分号后有一个空格- 逗号后面有一个空格
- 操作符后有一个空格:
+,-,--
等 - 不需要加空格在
(
之后与)
之前
实例:
a = (b + c) * d;
while (true)
DoSomething(a, b, c, d)
for (i = 0; i < 10; i++)
命名
1. 所有命名应该是英语
在国际合作开发中英语更有优势
2. 对语言元素使用适当的大小写
Tips
帕斯卡命名法(Pascal casing):一句文本中的每个单词的首字母为大写
驼峰命名法(Camel casing):一句文本中的每个单词的首字母为大写,除了文本的首字母
语言元素 | 命名法 | 样例 |
---|---|---|
Class, Struct | Pascal | AppDomain |
Interface | Pascal | IBusinessService |
Enumeration | Pascal | ErrorLevel |
Enumeration values | UPPER_CASE | FATAL_ERROR |
Event | Pascal | Click |
Public field | Camel | listItem |
Private field | Camel | _listItem |
Protected field | Camel | mListItem |
Constant field | UPPER_CASE | MAXIMUM_ITEM_NUMBER |
Constant local variable | UPPER_CASE | MAXIMUM_ITEM_NUMBER |
Read-only static field | Pascal | ReadValue |
Local variable | Camel | listOfValues |
Method | Pascal | ToString |
Namespace | Pascal | System.Drawing |
Parameter | Camel | typeName |
Type parameter | Pascal | TView |
Property | Pascal | BackColor |
3.避免使用缩略语
除非全名过长:
- 避免缩略超过5个字符
- 缩略语必须是广泛的被知道的
- 使用2个字符的大写缩略,使用Pascal命名方式对于长的缩略
优质:
UIControl
HtmlSource
劣质:
UiControl
HTMLSource
4. 布尔类型参数前缀
- Can
- Is
- Has
Tips
避免使用布尔参数作代表反面的性质,例如: 使用 IsInitialized
,而不是 IsNotInitialized
5. 在参数或属性中不要包含该类的名字
优质:
Customer.Name
劣质:
Customer.CustomerNam
注释
- 在注释定界符(//)和注释文本之间插入一个空格。
- 使用 //
- 使用内联注释来解释假设,已知问题和算法见解
- 不要使用内联注释来解释明显的代码。 编写良好的代码可以自我记录。
- 使用 // TODO
- 重构建议使用 // TODO :Refactor(username_optional)
语言规范
1. 不要忽略写访问权限
需要在声明时,写全访问权限
2. 使用C#内置的数据类型名字,而不是用.NET通用类型
优质:
short
int
long
string
劣质:
Int16
Int32
Int64
String
3. 不要使用var
容易不知道变量类型,不易阅读。
4.使用默认初始化器赋值,而不是单独写赋值
优质:
ProcessStartInfo startInfo = new ProcessStartInfo("myapp.exe")
{
StandardOutput = Console.Output,
UseShellExecute = true
};
劣质:
ProcessStartInfo startInfo = new ProcessStartInfo("myapp.exe");
startInfo.StandardOutput = Console.Output;
startInfo.UseShellExecute = true;
5. 代码用法
代码 | 形式 |
---|---|
变量 | 每一个声明一个变量 |
属性 | 不要加前缀 Get 和 Set 不想要额外变量,简单的声明 public int MyVariable { get; private set; } |
方法 | 最多7个参数 |
base 和 this | 只在构造方法或override 中使用 |
三元表达式 | 避免复杂的条件 |
迭代 | 不要在foreach 语句中修改枚举项 |
异常 | 不要将异常用于流控制 只抛出你能处理的 使用验证来避免异常 从 Execption 派生而不是ApplicationException |
事件 | 在触发是需要检测是否为空 |
锁 | 使用lock() 而不是Monitor.Enter() 不要锁对象的类型或者 this 锁一个私有的对象 |
Dispose() & Close() | 如果它提供了,就要使用 时常记得声明 |
类 | 避免放多个类在一个文件中 |
Finalizers | 不要用 使用C#的析构函数 不要创建 Finalize() 方法 |
6. 变量与类型
- 尽量初始化值在定义变量时
- 尽量选择最简单的数据类型
- 避免使用数字在代码里,使用常数或是枚举代替
- 声明
readonly
和static readonly
的变量而不是复杂的 常数类型 - 只对简单的类型声明常数
- 避免直接转化,使用
as
操作符然后检测是否为空object dataObject = LoadData(); DataSet dataSet = dataObject as DataSet; if(dataSet != null) {...}
- 始终使用
for
循环显式初始化引用类型的数组 - 避免对值类型装箱与拆箱
int count = 1; object refCount = count; // Implicitly boxed. int newCount = (int)refCount; // Explicitly unboxed.
- 尝试对字符串文字使用
@
前缀,而不是转义的字符串 - 使用
StringBuilder
连接大量字符串(在循环内) - 不要使用
""
或者string.Empty
来判断空字符串,而是用string.IsNullOrEmpty()
方法 - 避免在循环中分配隐藏的字符串。 使用
String.Compare()
区分大小写
// Bad!
int id = -1;
string name = "lance hunt";
for(int i=0; i < customerList.Count; i++)
{
if(customerList[i].Name.ToLower() == name)
{
id = customerList[i].ID;
}
}
// Good!
int id = -1;
string name = "lance hunt";
for(int i=0; i < customerList.Count; i++)
{
// The "ignoreCase = true" argument performs a
// case-insensitive compare without new allocation.
if(String.Compare(customerList[i].Name, name, true) == 0)
{
id = customerList[i].ID;
}
}
7. 流程控制
- 避免在条件表达式中调用方法
- 避免使用递归,使用循环代替
- 避免使用
foreach
遍历不可变的值类型集合。 例如:字符串数组 - 在
foreach
中不要修改枚举项 - 仅将三元条件运算符用于简单条件。避免复杂的或复合的三元运算。示例:
int result = isValid ? 9:4;
- 避免在
if
判断时,使用布尔值再加判断:// Bad! if (isValid == true) {...} // Good! if (isValid) {...}
- 避免在条件语句中赋值。示例 :
if((i=2)==2){...}
- 避免使用复合条件表达式,使用布尔变量将零件拆分为多个可管理的表达式
// Bad! if (((value > _highScore) && (value != _highScore)) && (value < _maxScore)) {...} // Good! isHighScore = (value >= _highScore); isTiedHigh = (value == _highScore); isValid = (value < _maxValue); if ((isHighScore && ! isTiedHigh) && isValid) {...}
- 仅将
switch/case
语句用于具有并行条件逻辑的简单操作 - 对于简短的条件序列和复杂的条件,优先使用嵌套
if/else
而不是switch/case
- 使用多态或委托来替换
switch/case
语句
8. 对象模型与API设计
- 避免过早的使用泛型
- 当设计已经很清晰了,才创建抽象类
- 做最简单的实现,这样重构才有意义
- 尽量使对象的生命周期是对用户是不可见的
- 始终把表现层和逻辑层分离
- 优先使用接口而不是抽象类
- 当使用设计模式时,在类名中加入设计模式名字后缀,如:
Brdge
、Adpter
、Factory
- 经常重构
参考
https://google.github.io/styleguide/csharp-style.html
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines