C#编码规范
一、命名习惯和风格
1、类和方法名采用Pascal风格
public class SomeClass
{
public SomeMethod()
{…}
}
2、局部变量和方法参数采用Camel风格
int number;
void MyMethod(int someNumber)
{…}
3.、接口名采用I作为前缀
interface IMyInterface
{…}
4、自定义属性类名采用Attribute作为后缀
5、自定义异常类名采用Exception作为后缀
6、采用动词-对象对命名方法,例如DoSomething()
7、有返回值的方法应该取名表示其返回值,例如
public string GetObjectState()
{…}
8、采用描述性的变量名
a) 避免采用单字母的变量名,如i或t;而是采用index或temp;
b) 对public和protected成员避免采用用匈牙利命名法(属性+类型+描述部分);例如不要使用public int m_bflag;
c) 不要采用缩写(例如将number缩写为num)。
9、总是使用C#预定义的类型,而不是使用System命名空间中的别名。例如:采用object不用Object,采用string不用String,采用int不用Int32。
10、采用有意义的命名空间名,例如产品名称或公司名称
11、避免使用类的全称,而是采用using语句
12、避免在命名空间内使用using语句
13、将所有framework命名空间名放在一起,后面放自定义或第三方的命名空间名
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using MyCompany;
using MyControls;
14、采用委托推断,不要显式实例化委托
15、严格遵守缩进格式
a) 缩进采用4个空格
b) 不用采用tab或非标准的缩进
16、注释缩进和其注释的代码在同一层次
17、所有成员变量应该定义在前面,和属性或方法间空开一行
public class MyClass
{
private int number;
private string name;
public void SomeMethod1()
{…}
public void SomeMethod2()
{…}
}
18、局部变量的定义尽可能靠近它的初次使用
19、文件名应该体现其包含的类
20、左右大括号{}总是放在新行中
二、编码习惯
1、避免在一个文件中放多个类
2、避免在同一文件中有多个命名空间
3、避免文件长度超过500行
4、避免方法定义超过25行
5、避免超过5个参数的方法,使用结构传递多个参数
6、每行应该不超过80个字符
7、不要手工编辑任何机器自动生成的代码
8、类及其成员、属性、方法以及其参数都必须采用“///” 进行注释
9、决不要硬编码数值,而总是声明一个常量
10、仅对本来就是常量的值使用const修饰符,例如一周的天数
11、避免对只读变量使用const修饰符,在此情况下,采用readonly修饰符
public class MyClass
{
public readonly int number;
public const int DaysInWeek = 7;
public MyClass(int someValue)
{
number = someValue;
}
}
12、每个方法都应该经过白盒测试
13、仅捕获已经显式处理了的异常
14、避免将错误代码作为方法的返回值
15、定义自定义异常时:
a) 从ApplicationException继承
b) 提供自定义的序列化
16、避免在一个程序集中有多个Main()方法
17、仅对最需要的类型标记为public,其他的标记为internal
18、避免采用friend程序集,因为这样增加了程序集间的耦合度
19、避免对枚举提供明确的值。
//正确:
public enum Color
{
Red,Green,Blue
}
//错误:
public enum Color
{
Red = 1,Green = 2,Blue = 3
}
20、避免对枚举指定类型。
//错误:
public enum Color : long
{
Red,Green,Blue
}
21、if语句总是使用括号,即使它包含一句语句
22、避免使用?:条件算符
23、避免在布尔条件语句中调用函数。赋值到局部变量并检查它们的值
bool IsEverythingOK()
{...}
//正确:
bool ok = IsEverythingOK();
if(ok)
{...}
//错误:
if(IsEverythingOK())
{...}
24、总是使用从0开始的数组
25、总是使用一个for循环显式地初始化一个引用类型的数组
MyClass[] array = new MyClass[100];
for(int index = 0; index < array.Length; index++)
{
array[index] = new MyClass();
}
26、不用提供public或protected成员变量,而是使用属性
27、避免使用new继承修饰符,而是使用override
28、避免显式类型转换,使用as算法防护性地转换类型。
Dog dog = new GermanShepherd();
GermanShepherd shepherd = dog as GermanShepherd;
if(shepherd != null)
{...}
29、调用委托前要始终检查委托是否为空
public class MySource
{
public event EventHandler MyEvent;
public void FireEvent()
{
EventHandler temp = MyEvent;
if(temp != null)
{
temp(this,EventArgs.Empty);
}
}
}
30、不要提供public的事件成员变量,而是使用事件访问器
public class MySource
{
MyDelegate someEvent;
public event MyDelegate HaveSomeEvent
{
add
{
someEvent += value;
}
remove
{
someEvent -= value;
}
}
}
31、总是使用接口
32、类和接口中方法和属性的比例至少是2:1
33、努力使每个接口拥有3-5个成员
34、每个接口不用超过20个成员
35、避免将事件作为接口成员
36、避免使用抽象方法,而是使用接口代替
37、在类层次中暴露接口
38、永远不要假设一种类型支持某个接口,防护性地检查是否支持该接口
SomeType obj1;
IMyInterface obj2;
obj2 = obj1 as IMyInterface;
if(obj2 != null)
{
obj2.Method1();
}
else
{…}
39、发布时可能修改的字符串永远不用硬编码,例如连接字符串
40、构建一个长字符串时,使用StringBuilder,不要用string
41、当提供静态成员变量时,总是提供一个静态构造函数
42、只要可以用前期绑定就不要用后期绑定
43、对应用程序进行日志和跟踪
44、除非在switch语句中跳转,永远不要用goto语句
45、switch语句中总是使用default用于加断言
int number = SomeMethod();
switch(number)
{
case 1:
Trace.WriteLine("Case 1:");
break;
case 2:
Trace.WriteLine("Case 2:");
break;
default:
Debug.Assert(false);
break;
}
46、除非在构造函数中调用另一个构造函数,否则不用使用this
public class MyClass
{
public MyClass(string message)
{}
public MyClass() : this("hello")
{}
}
47、除非为了解决调用基类构造函数时成员名的冲突,否则不要使用base访问基类的成员
public class Dog
{
public Dog(string name)
{}
virtual public void Bark(int howLong)
{}
}
public class GermanShepherd : Dog
{
public GermanShepherd(string name): base(name)
{}
override public void Bark(int howLong)
{
base.Bark(howLong);
}
}