.net设计规范
第三章 命名规范
大小写约定
camelCasing 内部字段,私有字段,局部变量,方法的形参
其他都用 PascalCasing
通用命名约定
程序集和DLL的命名
名字空间的命名
类,结构,接口的命名
类型成员的命名
第四章 类型设计规范
类型分类:
引用类型 :类,静态类,集合,数组,异常,修饰属性
值类型:结构,枚举
接口
类和结构之间的选择
结构:类型的实例比较小而且生命期比较短,或则被内联在其他对象中
在逻辑上代表一个独立的值,与基本类型相似
实例的大小小于16个字节
不可变
不需要经常被装箱
类和接口之间的选择
要用抽象类而不是接口来解除契约与实现之间的耦合
接口:需要提供多态层次结构的值类型
达到与多重继承相类似的效果
抽象类的设计
定义受保护的构造函数或内部构造函数
至少提供一个继承自该抽象类的具体类型
静态类的设计
定义为密封的,抽象的,并添加一个私有的实例构造函数
接口的设计
如果想让一组包括值类型在内的类型支持一些公共的API
如果想让已经继承其他基类的类型支持该接口提供的功能
结构的设计
不要为结构提供有默认的构造函数
不要定义可变的值类型
要为值类型实现 IEquatable<T>
枚举的设计
简单枚举
标记枚举
第五章 成员设计
方法,属性,事件,构造函数,字段
第八章 使用规范
数组
C#编程风格约定
要让右花括号单独占一行,除非它后面是else , else if , while
.net组件程序设计 c#编码标准
命名约定和风格
1. 类型名方法名常量沿用Pascal命名规范
2. 局部变量方法参数使用 camel命名规范
3. 接口名加前缀 I
4. 私有成员变量前加前缀 m_
5. 自定义属性类加后缀 Attribute
6. 自定义异常类加后缀 Exception
7. 方法命名使用动词对象对,如 ShowDialog
8. 有返回值的方法名中需要描述此返回值如 GetObjectState()
9. 使用描述性变量名:
a避免使用单个字母作为变量名,如i ,t 用 index , temp替代
b避免对公共成员或受保护成员使用匈牙利
c避免使用缩写如 number 写成 num
10.始终使用c#中的预定义类型,不使用system命名空间中的别名
11.对于范型用该类型的首字符代替
12.使用有意义的命名空间名称
13.避免使用完全限定类型名
14.避免在命名空间里面使用using语句
15.把所用的 framework命名空间放在一起,把自定义和第三方命名空间放在下面
16.采用委托推断,不显示实例化委托
17.严格保持缩进
18.注释缩进要和其注释的代码保持在同一列
19.所有注释都要通过拼写校验
20.所有的成员变量都必须在顶部声明用一行把他们和属性,方法隔开
21.定义局部变量时尽量使他靠近第一次使用的地方
22.文件名需能反映它所包含的类
23.当使用局部类型和指定局部文件时用局部的逻辑角色为他们命名
24.用 {换一行
25.对于匿名方法,与匿名委托声明对齐
26.无参数的匿名方法要使用()
编码实践
1. 避免把多个类放到同一个文件中
2. 避免在同一个文件中定义多个命名空间
3. 一个文件的代码避免500行
4. 方法要避免超过25行
5. 方法要避免超过5个参数用结构体传递多个参数
6. 每行不要超过80个字符
7. 不要手动编辑任何机器代码
8. 避免对显而易见的代码做注释
9. 仅对操作假设算法思路等写文档
10. 避免方法级别的文档
11. 除了 0,1不要用数值硬编码;声明一个常量代替
12. 仅对本来是常量的值使用 const
13. 避免对只读的变量使用 const 使用 readonly
14. 对任何假设都要断言
15. 每行代码都应该以白盒测试的方式运行过一遍
16. 仅捕获你需要显示处理的异常
17. 在抛出异常的catch语句中总是抛出最初异常
18. 避免把错误代码作为方法的返回值
19. 避免定义自定义的异常类
20. 自定义异常从exception派生,序列化
21. 避免在一个程序集中多个main()方法
22. 仅对最需要的类型为public 其他为internal
23. 避免友元程序集 friend assembly
24. 避免代码依赖于从一个特定位置运行的程序集
25. 最小化应用程序的程序集代码即exe客户端用类库来包含业务逻辑
26. 避免对枚举提供明确的值
27. 避免对枚举指定类型
28. if语句始终{}
29. 避免使用 ?:
30. 避免在布尔条件语句中调用函数
31. 总是使用从0开始的数组
32. 总是使用一个for循环显示地初始化一个引用类型的数组
33. 不要提供public protected成员变量使用属性
34. 避免使用new继承用override
35. 对非密封类总是把public protected方法为virtual
36. 不用unsafe代码
37. 用as操作符进行转换
38. 调用委托前检查是否为空
39. 不要提供public的事件成员变量使用事件访问器
40. 避免使用事件处理代理用 GenericEventHandler
41. 避免显示触发事件用 EventsHelper
42. 总是使用接口
43. 类和接口中方法和属性的个数2:1
44. 避免接口中只含有一个成员
45. 接口3到5个成员
46. 接口不超过20个成员实际不超过12
47. 避免把事件作为接口的成员
48. 使用抽象类的同时提供一个接口
49. 在类层次关系上暴露接口
50. 优先使用显式接口实现
51. 防御性是否支持该接口
52. 永远不要硬编码将呈现给用户的字符串而是使用资源
53. 永远不要硬编码部署时可以修改的字符串
54. 用string.empty代替“”
55. 构建一个长字符串时使用stringbuilder不用string
56. 不要为结构体提供方法
57. 提供静态成员变量时总是提供一个静态构造函数
58. 尽量用前期绑定
59. 对应用程序进行日志和跟踪
60. 除非在switch中用goto
61. swich中总是使用带断言default case
62. 除非在一个构造函数中调用另一个构造函数否则不要用this引用
63. 不要使用base访问基类的成员
64. 不要使用gc.addmemorypressure
65. 不要依赖handlerCollector
66. 模板实现Dispose() Finalize()方法
67. 默认unchecked模式溢出用checked
68. 避免方法调用的显式排除(#if-#endif)用条件方法替代
69. 不要在使用范型的代码中对system.object进行类型转换使用约束或as运算符
70. 不要在范型接口中定义约束条件用强类型代替
71. 不要在接口中定义与方法相关的约束条件
72. 推荐使用范型实现
73. 非范型接口衍生的范型接口显式接口实现
项目设置和项目结构
1. 总是以四级警告建立项目
2. 将警告当错误
3. 避免不要抑制特定的编译警告
4. 总是在应用程序的配置文件中显示的说明支持的运行时版本
5. 避免显示的自定义版本重定向和绑定到clr程序集
6. 避免显示预处理定义 (#define)
7. 不要在AssemblyInfo.cs中放任何逻辑
8. 除了AssemblyInfo.cs不要在任何文件中放程序集属性
9. 在AssemblyInfo.cs中提供所有字段的值
10. 所有程序集引用应该使用相对路径
11. 禁止在程序集间进行循环引用
12. 避免多模块的程序集
13. 避免使用Exception窗口篡改异常处理
14. 使用统一的版本号
15. App.config
16. 修改默认项目结构
17. 发布版中包含调式符号
18. 程序集签名
19. 使用密码保护的键值
与Framework相关的指南
多线程操作
1. 使用同步域
2. 不要向同步域外调用
3. 使用回调方法管理异步调用完成
4. 始终为你的线程命名
5. 不要对一个线程调用Suspend() Resume()
6. 对于强制上下文转换 Thread. Sleep(0);
7. 不要调用Thread.SpinWait()
8. 不要调用Thread.Abort()使用同步对象
9. 避免显示设置线程优先级
10. 不要读取ThreadState的属性值使用Tread.IsAlive()
11. 使用一个监视器来确定的关闭线程
12. 不要使用线程本地存储
13. 不要 Thread.MemoryBarrier()
14. 调用Thread.Join()之前检查是不是加入自己的线程
15. 使用lock()
16. 始终将lock()语句包含在其保护的对象之内
17. 同步方法代替lock
18. 避免片段缩定
19. 避免使用监视器来等待或激活对象使用手工方法或自动复位事件代替
20. 不要使用volatile变量
21. 避免增加线程池最大值
22. 不要堆砌lock()用WaitHandle.WaitAll();
序列化
1 .使用二进制格式器
2.将序列化事件处理方法标记为private
3.使用范型IGenericFormatter
4.将非密封类标记为可序列化
5.非密封类实现 IDserializationCallback确保子类调用基类的 OnDeserialization()
6.将无法序列化的成员变量定义为不可序列化的
7 .将一个序列化的代理标记为不可序列化
远程处理
1. 推荐使用管理式配置
2. 总是实现 single-call对象的IDisposable接口
3. 推荐使用TCP管道和二进制格式
4. 始终为singleton提供一个空的租约
5. 始终为客户端激活对象提供一个赞助方
6. 当客户端应用终止时注销赞助方
7. 始终将远程对象置于类库中
8. 避免使用SoapSuds.exe
9. 避免宿主在IIS
10. 避免使用单向管道
11. 始终将Remoting配置文件载入Main()函数
12. 避免对远程对象使用Activator.GetObject或Activator.CreateInstance()
13. 始终在客户端注册0号端口以允许返回
14. 在客户端和宿主机上将类型过滤级别提升为Full以允许回调
安全
1. 对你来说是公共的对应用来说是私有的程序集和组件要求有自己的强命名
2. 给应用程序配置文件加密和实施安全保护
3. 当导入一个互操作方法时断言非托管代码权限并要求合适的替代权限
4. 不要通过SuppressUnmanagedCodeSecurity属性来压制对非托管代码的访问
5. 不要使用TibImp.exe的undafe开关
6. 服务器 Microsoft ECMA和自身
7. 客户端仅保障客户端应用程序的正常执行回调服务器以及显示用户界面
8. 为了防止诱导攻击在程序集级别禁止所有对当前任务处理无关的权限
9. 始终在Main()方法中将主策略设置为Windows
10. 在没有要求一个替代权限时不要断言一个权限
C#编程风格
第一章 一般原则
1 .保持原有风格
2.坚持最小惊奇原则 简单性清晰性完整性一致性健壮性
3.第一次就做对
4.记录所有非规范行为
5.考虑采用代码检查工具强制遵循编码标准如工具Fxcop
第二章 格式
2.1空白
6.使用空白
7.使用缩进的语句块
8.缩进标记后的语句
9.不用”硬”制表符
10.切分长语句为多行语句
2.2花括号
11.按同一风格放置花括号
12.在流程控制结构中始终使用语句块
2.3类的组织
13.在源文件开始分组放置using指示符
14.将源代码组织到不同区域中
15.依可访问性排列类元素
16.单独声明每个变量和特性
第三章 命名
3.1一般原则
17.使用有意思的名称
18.根据含义而非类型来命名
19.使用熟悉的名称
20.不要用大小写来区分名称
21.避免使用过长的名称
22.加上元音—使用完整的单词
3.2缩略形式
23.除非全称太长,否则不用缩略形式
24.像普通词一样书写缩略词
3.3预处理器符号
25.用大写字母和下划线表示预处理器符号
26.给预处理器名称添加唯一前缀
3.4类型和常量
27.使用Pascal写法给命名空间,类,结构,属性,枚举,常量及函数命名
28.使用名词命名复合类型
29.用复数形式书写集合名称
30.给抽象基类型加上“Base”后缀
31.给实现一种设计模式的类添加模式名称
32.使用单个大写字母命名泛型参数
3.5枚举
33.用单数形式为枚举命名
34.用复数形式给位域命名
3.6接口
35.用大写字母”I”作为接口名称的前缀
36.使用名词或形容词给接口命名
3.7属性
37.依取值或赋值项给属性命名
38.避免过长的属性名称
39.用能体现布尔值特性的名称给布尔型属性命名
3.8方法
40.使用 Pascal写法为方法命名
41.用动词命名方法
42.避免过长的方法名
3.9变量和参数
43.使用骆驼写法给变量和方法参数命名
44.用名词命名变量
45.给成员变量名称加上前缀或后缀,使之与其他变量区分开
46.依所赋值的字段名称给构造函数和属性参数命名
47.用一系列标准名称为“一次性”变量和参数命名
3.10特性
48.给自定义特性实现加上”Attribute”后缀
3.11命名空间
49.用机构名称给根命名空间命名,加上项目,产品或小组名来缩小范围
3.12事件处理
50.使用适当的名称清晰区分事件处理部分
3.13异常
51.给自定义异常类型添加“Exception”后缀
第四章 文档
4.1一般原则
52.为使用接口的人编写软件接口文档
53.为维护者编写代码实现文档
54.保持注释和代码同步
55.尽早编写软件元素的文档
56.考虑全世界读者
57.在每个文件的开始添加版权,授权许可和作者信息
4.2 API
58.尽量使用c#语言内建的文档机制
59.编写重要前置条件,后置条件和不变条件的文档
60.编写线程同步需求
61.编写已知缺陷和不足
62.使用主动语态描述操作者,使用被动语态描述动作
63.当指称当前类的实例时,使用”this”,不用“the”
4.3内部代码
64.只在需要帮助别人理解代码的时候才添加内部注释
65.解释代码为什么要什么做
66.避免使用C风格的注释块
67.使用单行注释描述实现细节
68.避免使用行末注释
69.在多重嵌套控制结构中标出结束花括号
70.使用关键词标出待完成工作,未解决问题,错误和缺陷修正
71.标出空语句
第五章 设计
5.1工程
72.别怕做工程
73.简洁优于优雅
74.了解重用的代价
75.按约编程
76.选用适宜的工程方法
77.分隔不同的编程层
5.2类的设计
78.让类保持简单
79.定义派生类,使其可以用在任何可以使用其祖先类的地方
80.对于 is-a关系使用继承,对于 has-a关系使用包含
81.对于 is-a关系使用抽象基类,对于实现关系使用接口
5.3线程安全和并发
82.设计可重入的方案
83.只在合适的地方使用线程
84.避免不必要的同步
5.4效率
85.使用懒惰求值和懒惰初始化
86.重用对象以避免再次分配
87.最后再优化
88.避免创建不必要的对象
89.让clr处理垃圾回收
第六章 编程
6.1类型
90.使用内建的c#数据类型别名
91.避免使用内联字面量
92.避免不必要的值类型装箱
93.使用标准形式书写浮点字面量
94.为值语义使用结构
95.考虑在结构中覆盖等同方法和操作符
96.使用 @前缀转义整个字符串
97.避免代价昂贵的影藏字符串分配
98.采用有效的空字符串检测方法
99.只在必要时使用可空值
100.仅为支持机器生成代码使用部分类型
6.2语句和表达式
101.在复杂表达式中不要依赖操作符优先级
102.不用 true或 false测试相等
103.用等价方法替换重复出现的非普通表达式
104.在三元条件判断中避免使用复杂语句
105.使用 object.equals()测试引用类型的对象等同
6.3控制流程
106.避免在循环语句中使用 break和 continue语句
107.在方法中避免使用多个return语句
108.不要使用goto
109.不要使用try..throw…catch 来管理控制流程
110.在for语句内部声明循环变量
111.给所有switch语句的结尾添加default标记
6.4类
112.定义小类和小方法
113.从标准类型构造基础类
114.避免在用户可扩展的类层次结构中使用虚基类
115.声明所有成员的访问级别
116.将类标记为 sealed防止不想要的派生
117.避免使用internal声明
118.避免使用new来隐藏派生类型的成员
119.限制base关键字在子类构造函数和覆盖方法中的使用
120.在覆盖equals()方式时也覆盖opertor==和operator!=
121.在覆盖tostring()方法时,考虑覆盖隐式字符串转换操作符
122.用相反功能的方法来实现方法
6.5生命周期
123.初始化所有变量
124.总是构造在有效状态的对象
125.为增加的透明性和com互操作性声明显示默认构造函数
126.声明构造函数为保护的,禁止直接实例化
127.总是在派生构造函数的初始化列表中列出全部基构造函数
128.使用嵌套的构造函数消除过多代码
129在引用外部资源的类中实现IDisposable
6.6字段和属性
130.声明所有字段为私有访问级别,使用属性提供访问
131.只为简单,低成本,与顺序无关的访问使用属性
6.7方法
132.避免传递过多参数
133.检验参数值有效性
6.8特性
134.使用system.obsoleteattribute弃用api
135.考虑新类是否可被串行化
136.使用system.flagsattribute指明位域
6.9范型
137.范型类型胜过未指定类型或强类型类
6.10枚举
138.使用枚举而非布尔来改善参数可读性
139.使用枚举而非整形常量
140.创建0值枚举元素表示未初始化
141.验证枚举值
6.11类型安全,强制转换和转换
142.避免强制转换,并且不要强迫别人使用强制转换
143. as操作符胜过直接强制转换
144.使用多态而不频繁使用is或 as
6.12错误处理和调试
145.使用返回代码报告预期的状态改变
146.使用异常强迫获得编程契约
147.不要静默地接受或忽略非预期的运行时错误
148.使用断言或异常报告非预期的运行时错误
149.使用异常来报告可恢复错误
150.使用try…finally或 using语句
151.尽可能抛出最具体的异常
152.只捕获你能处理的异常
153. catch抛出新异常,不要丢弃异常信息
154.依异常类型特殊性级别排列catch块
155.不要在finally块中抛出异常
156.仅特别处理才创建自定义异常
157.定义新异常类,从applicationexception派生
158.使用内建的调试类调式代码
6.13事件委托和线程
159.使用lock()
160.只缩定私有对象
第七章 打包
7.1文件
161.在单个文件中放置命名空间作用域内的每个元素
162.用元素名作为文件名
7.2命名空间
163.不要污染框架命名空间
164.为每个命名空间创建单独的目录
165.将常被共同使用,修改和发布或互相依赖的类型放到同一个命名空间下
166.在分开的程序集中隔离不稳定的类
167.最大抽象化以最大稳定性
168.将高级设计和架构捕获为稳定抽象,组织到稳定命名空间中
7.3程序集
169.让程序集和命名空间的名字保持一致
170.避免让难以修改的程序集依赖于易于修改的程序集
171.手工增加程序集版本号
172.只把单个类暴露给com不暴露整个程序集
173.将有不安全代码的类放到单独程序集中
174.静态连接本地代码
net设计规范(2)
1. 要把PascalCasing用于由多个单词构成的名字空间,类型以及成员的名字.
2. 要把camelCasing用于参数的名字.
3. 要把两个字母的首字母缩写词全部大写,除非是camelCasing风格参数名的第一个单词
System.IO
Public void StartIO(Stream ioStream)
4. 要把三个或三个以上字母组成的首字母缩写词的第一个字母大写。只有第一个字母大写,除非是camelCasing风格参数名的第一个单词.
System.Xml
Public void ProcessHtmlTag(string htmlTag)
5. Jeffrey Richter : 所有的字段为私有的,实例字段 m_前缀,静态字段 s_前缀
6. 要优先使用后缀而不是前缀来表示已有API的新版本
7. 要用名词或名词短语来给类和结构命名
8. 要用形容词短语给接口命名
9. 考虑在派生类的末尾使用基类的名字
10. 要用单数名词来命名枚举类型
11. 要用复数名词来命名表示位域的枚举类型
12. 要用动词或动词短语来命名方法
13. 要用名词,名词短语或形容词来命名属性
14. 要用描述集合中项目短语的复数形式来命名集合属性
15. 要用动词或动词短语来命名事件
16. 要用名词,名词短语或形容词来命名字段
17. 结构,枚举是值类型
18. 类,集合,数组,异常,修饰属性是引用类型
19. 如果该类型的实例比较小而且生命期比较短,或者经常被内嵌在其他对象中用结构
20. 如果需要提供多态层次结构的值类型用接口
21. 要为抽象类定义受保护的构造函数或内部构造函数
22. 要为值类型实现IEquatable<T>
23. 要优先使用枚举而不要使用静态常量
24. 要在想让一个类型能够访问外层类的成员时才使用嵌套类型
25. 要把最长的重载成员定义成重载成员中唯一的虚成员
26. 考虑使用属性—如果该成员表示类型的一种逻辑属性
27. 如果属性的值存储在进程内存中,而且提供属性的目的仅仅为了访问
28. 考虑通过索引器的方式让用户访问存储在内部数组中的数据
29. 考虑为代表元素集合的类型提供索引器
30. 要把静态构造函数声明为私有的
31. 要用受保护的虚方法来触发事件
32. 不要使用弱类型集合
33. 不要使用ArrayList或List<T>要用Collection<>
34. 不要使用Hashtable或Dictionary<>要用IDictionary<>
35. 要为值类型实现IEquatable<T>
36. 避免使用System.DBNull,要优先使用Nullable<T>