IDesign C#编程规范[转]
原文转自:http://www.cnblogs.com/ShiningRay/archive/2005/04/11/135263.html
命名规则和风格
1. 类和方法名采用Pascal风格
public class SomeClass
{
public SomeMethod(){}
}
2. 局部变量和方法参数采用camel风格
int number;
void MyMethod(int someNumber)
{}
3. 接口名采用I作为前缀
interface IMyInterface
{..}
4. 私有成员变量采用m_作为前缀
public class SomeClass
{
private int m_Number;
}
5. 自定义属性类名采用Attribute作为后缀
6. 自定义异常类名采用Exception作为后缀
7. 采用动词-对象对命名方法,例如ShowDialog()
8. 有返回值的方法应该取名表示其返回值,例如GetObjectState()
9. 采用描述性的变量名。
a) 避免采用单字母的变量名,如i或t;而是采用index或temp。
b) 对public和protected成员避免采用用匈牙利命名法。
c) 不要采用缩写(例如将number缩写为num)。
10. 总是使用C#预定义的类型,而不是使用System命名空间中的别名。例如:采用object不用Object,采用string不用String,采用int不用Int32。
11. 对于泛型,类型采用大写字母。当处理.NET类型Type时保留后缀Type。
// 正确:
//Correct:
public class LinkedList
// 避免使用:
//Avoid:
public class LinkedList
12. 采用有意义的命名空间名,例如产品名称或公司名称。
13. 避免使用类的全称,而是采用using语句。
14. 避免在命名空间内使用using语句。
15. 将所有framework命名空间名放在一起,后面放自定义或第三方的命名空间名。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using MyCompany;
using MyControls;
16. 采用委托推断,不要显式实例化委托。
delegate void SomeDelegate();
public void SomeMethod()
{}
SomeDelegate someDelegate = SomeMethod;
17. 严格遵守缩进格式。
a) 缩进采用3个空格。
b) 不用采用tab或非标准的缩进,如1、2或4个空格。
18. 注释缩进和其注释的代码在同一层次。
19. 所有注释要经过拼写检查。拼写错误的注释表明开发的草率。
20. 所有成员变量应该定义在前面,和属性或方法间空开一行。
public class MyClass
{
int m_Number;
string m_Name;
public void SomeMethod1()
{}
public void SomeMethod2()
{}
}
21. 局部变量的定义尽可能靠近它的初次使用。
22. 文件名应该体现其包含的类。
23. 当使用partial类型且每部分分配一个文件时,以类型名加P和序数命名每个文件。
//In MyClassP1.cs
public partial class MyClass
{}
//In MyClassP2.cs
public partial class MyClass
{}
24. 左大括号总是放在新行中。
25. 匿名方法模仿普通方法的布局,和匿名委托定义放在一行。
a) 遵守将左大括号放在新行的规则。
delegate void SomeDelegate(string someString);
//正确
//Correct:
public void InvokeMethod()
{
SomeDelegate someDelegate = delegate(string name)
{
MessageBox.Show(name);
};
someDelegate("Juval");
}
//避免采用:
//Avoid
public void InvokeMethod()
{
SomeDelegate someDelegate = delegate(string name){MessageBox.Show(name);};
someDelegate("Juval");
}
26. 没有参数的匿名方法使用空括号。
a) 仅当匿名方法可能被用于任何委托时省略括号。
delegate void SomeDelegate();
//Correct
SomeDelegate someDelegate1 = delegate()
{
MessageBox.Show("Hello");
};
//Avoid
SomeDelegate someDelegate1 = delegate
{
MessageBox.Show("Hello");
};
2 编码惯例
1. 避免在一个文件中放多个类。
2. 一个文件应该只对一个命名空间提供类型。避免在同一文件中有多个命名空间。
3. 避免文件长度超过500行(除了机器自动产生的代码)。
4. 避免方法定义超过25行。
5. 避免超过5个参数的方法。使用结构传递多个参数。
6. 每行应该不超过80个字符。
7. 不要手工编辑任何机器生成的代码。
a) 如果修改机器生成的代码,修改代码格式和风格以符合本编码标准。
b) 尽可能采用partial类以分解出需要维护的部分。
8. 避免对显而易见的内容作注释。
a) 代码应该是自解释的。 由可读性强的变量和方法组成的好的代码应该不需要注释。
9. 仅对操作的前提、内在算法等写文档。
10. 避免方法级的文档。
a) 对API文档采用大量的外部文档。
b) 方法级注释仅作为对其他开发人员的提示。
11. 决不要硬编码数值, 而总是声明一个常量。
12. 仅对本来就是常量的值使用const修饰符,例如一周的天数。
13. 避免对只读变量使用const修饰符。在此情况下,采用readonly修饰符。
public class MyClass
{
public readonly int Number;
public MyClass(int someValue)
{
Number = someValue;
}
public const int DaysInWeek = 7;
}
14. 对任何假设采用assert。
a) 平均地,每5行中就有一行是断言。
using System.Diagnostics;
object GetObject()
{
object obj = GetObject();
Debug.Assert(obj != null);
15. 每行代码应该经过白盒测试。
16. 仅捕获已经显式处理了的异常。
17. 在抛出异常的catch语句中,总是抛出最初异常以保持最初错误的堆栈位置。
catch(Exception exception)
{
MessageBox.Show(exception.Message);
throw; //Same as throw exception;
}
18. 避免将错误代码作为方法的返回值。
19. 避免定义自定义的异常类。
20. 定义自定义异常时:
a) 从ApplicationException继承
b) 提供自定义的序列化。
21. 避免在一个程序集中有多个Main()方法。
22. 仅对最需要的类型标记为public,其他的标记为internal。
23. 避免采用friend程序集,因为这样增加了程序集间的耦合度。
24. 避免使用依赖于从特定位置运行的程序集的代码。
25. 尽量减少应用程序集(客户端EXE程序集)的代码。采用类库而不要包含业务逻辑层代码。
26. 避免对枚举提供明确的值。
//Correct
public enum Color
{
Red,Green,Blue
}
//Avoid
public enum Color
{
Red = 1,Green = 2,Blue = 3
}
27. 避免对枚举指定类型。
//Avoid
public enum Color : long
{
Red,Green,Blue
}
28. if语句总是使用括号,即使它包含一句语句。
29. 避免使用?:条件算符。
30. 避免在布尔条件语句中调用函数。赋值到局部变量并检查它们的值。
bool IsEverythingOK()
{...}
//避免:
if(IsEverythingOK())
{...}
//采用:
bool ok = IsEverythingOK();
if(ok)
{...}
31. 总是使用从0开始的数组。
32. 总是使用一个for循环显式地初始化一个引用类型的数组。
public class MyClass
{}
MyClass[] array = new MyClass[100];
for(int index = 0; index < array.Length; index++)
{
array[index] = new MyClass();
}
33. 不用提供public或protected成员变量,而是使用属性。
34. 避免使用new继承修饰符,而是使用override。
35. 对非密封类总是将public和protected方法标记为virtual。
36. 除非涉及到互操作,永远不要用不安全的代码。
37. 避免显式类型转换。使用as算法防护性地转换类型。
Dog dog = new GermanShepherd();
GermanShepherd shepherd = dog as GermanShepherd;
if(shepherd != null)
{...}
38. 类成员有委托时:
a) 使用前将委托复制到局部变量,以避免并发冲突。
b) 调用前始终检查委托是否为空。
public class MySource
{
public event EventHandler MyEvent;
public void FireEvent()
{
EventHandler temp = MyEvent;
if(temp != null)
{
temp(this,EventArgs.Empty);
}
}
}
39. 不要提供public的事件成员变量,而是使用事件访问器。
public class MySource
{
MyDelegate m_SomeEvent;
public event MyDelegate SomeEvent
{
add
{
m_SomeEvent += value;
}
remove
{
m_SomeEvent -= value;
}
}
}
40. 使用Programming .NET Components中定义的EventsHelper类安全地发布事件。
41. 总是使用接口。
a) 参见Programming .NET Components第一和第三章。
42. 类和接口中方法和属性的比例至少是2:1。
43. 避免使用一个成员的接口。
44. 努力使每个接口拥有3-5个成员。
45. 每个接口不用超过20个成员。
a) 12可能是实际应用的极限了。
46. 避免将事件作为接口成员。
47. 避免使用抽象方法,而是使用接口代替。
48. 在类层次中暴露接口。
a) 参见Programming .NET Components第三章。
49. 优先使用明确的接口实现。
a) 参见Programming .NET Components第三章。
50. 永远不要假设一种类型支持某个接口。防护性地检查是否支持该接口。
SomeType obj1;
IMyInterface obj2;
/* Some code to initialize obj1, then: */
obj2 = obj1 as IMyInterface;
if(obj2 != null)
{
obj2.Method1();
}
else
{
//Handle error in expected interface
}
51. 将呈现给用户的字符串永远不用硬编码,而是使用资源。
52. 发布时可能修改的字符串永远不用硬编码,例如连接字符串。
53. 构建一个长字符串时,使用StringBuilder,不要用string。
54. 避免提供带结构的方法。
a) 参数化的构造函数是鼓励使用的。
b) 可以重载算符。
55. 当提供静态成员变量时,总是提供一个静态构造函数。
56. 只要可以用前期绑定就不要用后期绑定。
57. 对应用程序进行日志和跟踪。
58. 除非在switch语句中跳转,永远不要用goto语句。
59. 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;
}
60. 除非在构造函数中调用另一个构造函数,否则不用使用this。
//Example of proper use of this
public class MyClass
{
public MyClass(string message)
{}
public MyClass() : this("hello")
{}
}
61. 除非为了解决调用基类构造函数时成员名的冲突,否则不要使用base访问基类的成员。
//Example of proper use of 抌ase?
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);
}
}
62. 根据Programming .NET Components第四章中的模板实现Dispose()和Finalize()方法。
63. 使用泛型的代码中避免与System.Object进行类型转换,而是使用限制或as算符。
class SomeClass
{}
//避免 :
class MyClass
{
void SomeMethod(T t)
{
object temp = t;
SomeClass obj = (SomeClass)temp;
}
}
//正确 :
class MyClass
{
void SomeMethod(T t)
{
SomeClass obj = t;
}
}
64. 泛型接口不要定义限制。接口层的限制通常能用强类型代替。
public class Customer
{...}
//避免
public interface IList
{...}
//正确
public interface ICustomerList : IList
{...}
65. 不要在接口中定义与方法相关的限制。
66. 在数据结构中总是优先使用C#泛型。
3 项目设置和项目结构
1. 总是以4级警告建立项目(图略)。
2. 在发布版中将警告作为错误(注意这不是VS.NET的缺省设置)(图略)。
a) 虽然是可选的,本标准也推荐在调试版中将警告作为错误。
3. 永远不要抑制特定的编译警告(图略)。
4. 总是在应用程序的配置文件中显式地说明支持的运行时版本。参见Programming .NET Components第五章。
5. 避免显式地自定义版本改向和绑定到CLR程序集。
6. 避免显式的预编译定义(#define)。使用项目设置定义条件编译常量。
7. 不要在AssemblyInfo.cs中放任何逻辑。
8. 除了在AssemblyInfo.cs,不要在任何文件中放程序集属性。
9. 在AssemblyInfo.cs中提供所有字段,例如公司名称、描述、版权等。
10. 所有程序集应该使用相对路径引用。
11. 不允许在程序集中循环引用。
12. 避免多模块的程序集。
13. 缺省总是以非检查的方式运行(为了性能考虑),但是对易于溢出或下溢的操作显式使用检查模式(图略)。
int CalcPower(int number,int power)
{
int result = 1;
for(int count = 1;count <= power;count++)
{
checked
{
result *= number;
}
}
return result;
}
14. 避免使用Exception窗口(Debug|Exceptions)篡改异常处理。
15. 努力对同一逻辑应用程序中(通常是一个解决方案)的所有程序集和客户端使用统一的版本号。
16. Visual Studio.NET应用的配置文件命名为App.config,并将其包括在项目中。
17. 避免使用显式代码来排除方法(#if#endif),而是使用条件方法。
public class MyClass
{
[Conditional("MySpecialCondition")]
public void MyMethod()
{}
}
18. 将VS.NET缺省的项目结构改为标准的布局,对项目文件夹和文件应用统一的结构。
19. 链接一个包含所有解决方案级信息的全局共享文件(图略)。
20. 制表符选用"插入空格",使用3个空格代替制表符。
a) 在工具|选项|文本编辑器|C#|制表符中设置
21. 发布版中应该包含调试符号。
22. 总是对程序集签名,包括客户端应用程序。
23. 总是使用项目的SNK文件对互操作程序集签名(图略)。
4 Framework特别指导
4.1 数据访问
1. 总是使用类型安全的数据集或者数据表。避免使用原始的ADO.NET。
2. 访问数据库时总是使用事务。
a) 总是使用服务组件事务。
b) 不要使用ADO.NET事务。
3. 总是将事务隔离级别设置为序列的。
a) 使用其它隔离级别需要管理层决定。
4. 不要使用服务器浏览器将数据库连接拖到Windows表单、ASP.NET表单或Web服务中。这样做耦合了界面层和数据层。
5. 避免使用SQL Server验证。
a) 而是使用Windows验证。
6. 将访问SQL Server的组件以调用该组件客户端不同的身份运行。
7. 总是在高层用类型安全的类包装存储过程。仅在那个类中调用存储过程。
8. 避免在存储过程中放任何逻辑。
a) 如果存储过程中有IF,你可能犯了错误。
待续。忽然想到曾阅读过一篇关于business layer的文章,总体是责问有多少程序真正有business layer,文中甚至倡议presentation layer中不要引用System.Data命名空间,你做得到吗?小鸡射手还不行,嘻嘻...