@H_
301_0@ .net约定、惯
用法与模式
@H_
301_0@ 第一章概述
@H_
301_0@ PC早期底层编程工具:编译器、API、标准程序库
@H_
301_0@ OOP产生框架的概念
@H_
301_0@ 为确保可重用组件的一致性,需要共同的规则
@H_
301_0@ 1.1精心设计的框架所应具备的品质
@H_
301_0@ 简单:
功能强大和简单之间进行平衡
@H_
301_0@ 设计代价高:对
用户来说,框架实现细节不可见
@H_
301_0@ 充满利弊权衡:
@H_
301_0@ 应该借鉴过去:借鉴经过实践检验的设计
@H_
301_0@ 要考虑未来发展:对框架将来的发展能力有怎样的影响
@H_
301_0@ 良好的集成性:
@H_
301_0@
一致性:
@H_
301_0@
@H_
301_0@ 第二章框架设计基础
@H_
301_0@ 要设计既
功能强大又易于使用的框架:简单的东西是简单的,复杂的东西是可能的;80/20
@H_
301_0@ 要明确的为具有不同编程风格、需求、技能以及不同编程语言的人设计框架
@H_
301_0@ 要了解那些使用多语言框架的广大开发人员
@H_
301_0@ 2.1渐进框架
@H_
301_0@ .net framework:覆盖广大开发人员但不是所有人员
@H_
301_0@ 2.2框架设计的基本原则
@H_
301_0@ 1场景驱动设计的原则
@H_
301_0@
在设计框架时,必须从一组使用场景以及实现这些场景的样例代码开始:集中精力在常用场景
@H_
301_0@ 要确保对任何包含公用API的特性的设计来说,其核心部分都是API设计规范。
@H_
301_0@ 要为每个主要的特性域定义一些最常用的使用场景。
@H_
301_0@ 要确保使用场景与适当的抽象层次相对应。
@H_
301_0@ 要以这样的方式来设计API:先为主要的使用场景来编写样例
代码,然后再定义对象模型来
支持这些
代码。
@H_
301_0@ 要用至少两种不同的编程语言来为主要场景编写案例
代码。
@H_
301_0@ 不要在设计框架的公用API时完全依赖于标准的设计
方法。
@H_
301_0@ 要安排可用性研究来测试用于主要场景的API。
@H_
301_0@ 2低门槛原则
@H_
301_0@
框架必须以易于实验的方式来为普通用户提供一个低门槛
@H_
301_0@ 确保每个特性域的名字空间只包含用于常用场景的类型。用于高级场景的类型放入子名字空间。
@H_
301_0@ 要为构造
函数和
方法提供简单的重载
函数。
@H_
301_0@ 不要在为主要场景设计的类型中包含用于高级场景的
方法。
@H_
301_0@ 不要要求
用户在基本的场景中
显示地实例化一个以上的类型。
@H_
301_0@ 不要要求
用户在为基本使用场景编写
代码之前就进行大量地初始化。
@H_
301_0@ 要尽可能地为所有的
属性和参数提供合适的默认值。
@H_
301_0@ 要通过异常来传达对API的误用。
@H_
301_0@ 3自说明对象模型原则
@H_
301_0@
在简单的使用场景中,一定要让框架无需文档就能使用。
@H_
301_0@ 要确保API是直观的,无需查阅参考文档就能用于简单场景。
@H_
301_0@ 要为所有的API提供优秀的文档。
@H_
301_0@ 要在规范检查中重视标识符
名称的选择。
@H_
301_0@ 不要担心标识符的名字太冗长。
@H_
301_0@ 要在设计过程的早期让
用户教育专家参与。
@H_
301_0@ 考虑把最好的名字留给最常用的类型。
@H_
301_0@ 要通过异常消息告诉开发人员对框架的误用。
@H_
301_0@ 要尽可能的提供强类型API。
@H_
301_0@ 要确保与.net框架或客户可能会使用的其他框架保持一致。
@H_
301_0@ 避免在主要场景的API中使用过多的抽象。
@H_
301_0@ 4分层架构原则
@H_
301_0@
分层设计使得在单个框架中同时提供强大的功能和易用性成为可能。
@H_
301_0@ 考虑对框架进行分层,使高层API能提供最佳的开发效率,低层API能提供最强大的
功能和最丰富表现力。
@H_
301_0@ 避免把高层API和低层API放在同一个命名空间中,如果低层API非常复杂的话。
@H_
301_0@ 要确保单个特性域中,不同的层能很好的集成在一起。
@H_
301_0@
@H_
301_0@ 第三章命名规范
@H_
301_0@ 3.1大小写约定
@H_
301_0@ PascalCasing(除参数名外,命名空间,类型,成员):首字母大写,不使用下划线。
两字母长度缩写词是特例
@H_
301_0@ camelCasing参数名:第一单词小写,其余单词首字母大写。
@H_
301_0@ 两字母缩写词全部大写,除非是camelCasing的第一个单词。
@H_
301_0@ 复合词当成一个单词。
@H_
301_0@ 不要以为所有的编程语言都是区分大小写的,不应该仅仅通过大小写来区分名字。
@H_
301_0@ 3.2通用命名约定
@H_
301_0@ 要为标识符选择易于阅读的名字。
@H_
301_0@ 要更看重可读性,而不是更看重简短性。
@H_
301_0@ 不要使用下划线、连字符及其他不是字母和数字的字符。
@H_
301_0@ 不要使用匈牙利命名法。
@H_
301_0@ 避免使用与常用的编程语言的关键字有冲突的标识符。
@H_
301_0@ 不要使用缩写词作为标识符名字的一部分。
@H_
301_0@ 不要使用未被广泛接收的首字母缩写词。
@H_
301_0@ 避免使用语言特有的关键字。
@H_
301_0@ 要在创建已有API的新版本时使用与旧API相似的名字。
@H_
301_0@ 要优先使用后缀表示API的新版本。
@H_
301_0@ 要使用数字后缀表示API的新版本。
@H_
301_0@ 可考虑使用全新但有意义的标识符。
@H_
301_0@ 不要使用类似Ex的后缀表示新版本。
@H_
301_0@ 对64位整数进行操作的新API使用64后缀。
@H_
301_0@ 3.3程序集和DLL的命名
@H_
301_0@ 要为程序集和DLL选择
提示性的名字。不一定和命名空间对应。
@H_
301_0@ 考虑命名模式:Company.Component.dll
@H_
301_0@ 3.4命名空间的命名
@H_
301_0@ Company.(Product|Technology)[.Feature][.Subnamespace]
@H_
301_0@ 用公司
名称作命名空间前缀。
@H_
301_0@ 要用稳定的、与版本无关的产品
名称作空间的第二层。
@H_
301_0@ 不要根据公司的组织架构决定命名空间层次。
@H_
301_0@ 使用Pascal大小写,用点分割。
@H_
301_0@ 考虑适当的时候用复数形式。
@H_
301_0@ 不要用相同的名字命名空间和类型。
@H_
301_0@ 不要引入太一般化的类型名。
@H_
301_0@ 1应用程序模型命名空间System.Web.UI,System.Windows
@H_
301_0@ 不要给位于同一个应用程序模型的命名空间中的类型起相同的名字。
@H_
301_0@ 2基础设施命名空间System.Windows.Forms.Design
@H_
301_0@ 3核心名字空间 除1,2外的System
@H_
301_0@ 不要给类型起会与核心命名空间中的任何类型冲突的名字。
@H_
301_0@ 4技术命名空间组
@H_
301_0@ 不要给类型起会与技术空间中其他类型冲突名字。
@H_
301_0@ 不要在技术空间与应用模型空间的类型间引入名字冲突。
@H_
301_0@ 3.5类、结构和接口的命名
@H_
301_0@ 如果无法为类型提供名词词组,那么应重新考虑总体设计。
@H_
301_0@ 要用名词词组给类型命名,少数情况可用形容词词组。
@H_
301_0@ 不要给类名加前缀。
@H_
301_0@ 考虑让派生类的名字以基类结尾。
@H_
301_0@ 要让接口的名字以I开头。
@H_
301_0@ 要确保接口的标准实现和接口只相差一个I前缀。
@H_
301_0@ 1泛型类型参数的命名
@H_
301_0@ 要用描述性的名字来命名泛型类型参数。
@H_
301_0@ 考虑用T来命名参数类型。
@H_
301_0@ 要在描述性类型参数加T前缀。
@H_
301_0@ 考虑参数名中
显示限制。
@H_
301_0@ 2常用类型的命名
@H_
301_0@ 派生或实现核心类型规则:
@H_
301_0@ Attribute,EventArgs,Exception,Dictionary,Stream后缀
@H_
301_0@ Delegate派生类加事件处理加EventHandler,事件处理之外加Callback,不要Delegate后缀
@H_
301_0@ IEnumerable,ICollection,IList及对应泛型加Colletion后缀
@H_
301_0@ IPermission,AccessPermission加Permission后缀
@H_
301_0@ 不要派生自ENUM,用关键字代替
@H_
301_0@ 3枚举类型的命名
@H_
301_0@ 要用单数名词表示enum类型,除非表示位域。
@H_
301_0@ 要用复数名词来表示位域的枚举类型。
@H_
301_0@ 不要给枚举类型
添加Enum后缀。
@H_
301_0@ 不要给枚举类型
添加Flag后缀。
@H_
301_0@ 不要给枚举类型值的名字
添加前缀。
@H_
301_0@ 3.6类型成员的命名
@H_
301_0@ 1
方法命名
@H_
301_0@ 要用动词或动词词组来命名
方法。
@H_
301_0@ 2
属性的命名
@H_
301_0@ 要用名词或形容词词组来命名
属性。
@H_
301_0@ 不用让
属性名看起来与get
方法名相似。
@H_
301_0@ 要用肯定性的短语来命名布尔
属性。
@H_
301_0@ 考虑用
属性的类型名来命名
属性。
@H_
301_0@ 3事件的命名
@H_
301_0@ 要用动词或动词短语来命名事件。
@H_
301_0@ 要用现在时和过去时来赋予事件名以之前和之后的状态。
@H_
301_0@ 不要用Before或After前缀或后缀。
@H_
301_0@ 要在命名事件处理
函数时
加上EventHandler后缀。
@H_
301_0@ 要在事件处理
函数中用sender和e作为两个参数的名字。
@H_
301_0@ 要在命名事件的参数时
加上EventArgs后缀。
@H_
301_0@ 4字段的命名
@H_
301_0@ 适用于静态公有字段和静态受保护字段
@H_
301_0@ 要用名词或名词短语来命名字段。
@H_
301_0@ 不要
添加字段前缀。
@H_
301_0@ 3.7参数的命名
@H_
301_0@ 命名参数时使用camelCasing风格。
@H_
301_0@ 要使用具有描述性的参数名。
@H_
301_0@ 考虑根据参数的意思而不是类型来命名参数。
@H_
301_0@ 3.8资源的命名
@H_
301_0@ 和
属性命名相似。
@H_
301_0@ 要使标识符的名字具有描述性而不是变短。
@H_
301_0@ 不要使用各CLR语言特有的关键字。
@H_
301_0@ 要在命名资源时仅使用字母数字下划线。
@H_
301_0@ 要用点号来为标识符清楚的划分层次。
@H_
301_0@ 要在为异常的消息资源命名时遵循异常的类型名
加上点然后
加上简短的标识符
@H_
301_0@
@H_
301_0@ 第四章类型设计规范
@H_
301_0@ 要确保每个类型由一组定义明确、相互关联的成员组成,而不是一些无关
功能的
随机集合。
@H_
301_0@ 4.1类型和名字空间
@H_
301_0@ 要用名字空间把类型组织成一个相关的特性域的组织结构。
@H_
301_0@ 避免非常深的名字空间层次。
@H_
301_0@ 避免有太多的名字空间。
@H_
301_0@ 避免把为高级场景设计的类型和为常见编程而设计的类型放在同一个命名空间中。
@H_
301_0@ 不要不指定命名空间就定义类型。
@H_
301_0@ 1Design子名字空间
@H_
301_0@ 要用.Design后缀的名字空间来容纳那些为基本名字空间提供设计时
功能的类型。
@H_
301_0@ 2Permissions子名字空间
@H_
301_0@ 要用. Permissions后缀的名字空间来容纳那些为基本名字空间提供
自定义许可的类型。
@H_
301_0@ 3Interop子名字空间
@H_
301_0@ 要用. Interop后缀的名字空间来容纳那些为基本名字空间提供互操作
功能的类型。
@H_
301_0@ 要用. Interop后缀的名字空间来容纳所有PLA中的
代码。
@H_
301_0@ 4.2类和结构之间的选择
@H_
301_0@ 不要定义结构,除非有如下特征:逻辑上代表独立的值、实例小于16字节、不可变;实例比较小周期比较短,经常内嵌。
@H_
301_0@ 4.3类和接口之间的选择
@H_
301_0@ 要优先采用类而不是接口。
@H_
301_0@ 要用抽象类而不是接口来解除协定与实现之间的耦合。
@H_
301_0@ 要定义接口,如果需要提供一个多态的值类型层次结构的话。
@H_
301_0@ 考虑通过定义接口来达到与多重继承相类似的
效果。
@H_
301_0@ 4.4抽象类的设计
@H_
301_0@ 不要在抽象类型中定义公有的或内部受保护的构造
函数。
@H_
301_0@ 要为抽象类定义受保护的构造
函数或内部构造
函数。
@H_
301_0@ 要为你发布的抽象类提供至少一个继承自该类的具体类型。
@H_
301_0@ 4.5静态类的设计
@H_
301_0@ 要尽量少用静态类。
@H_
301_0@ 不要把静态类当作是杂物箱。
@H_
301_0@ 不要在静态类中声明或覆盖实例成员。
@H_
301_0@ 要把静态类定义成密封的抽象的,并
添加一个私有的实例构造
函数,如果你的编程语言没有提供对静态类的
支持。
@H_
301_0@ 4.6接口的设计
@H_
301_0@ 要定义接口,如果你需要
包括值类型在内的一组类型
支持一些公共的API。
@H_
301_0@ 考虑定义接口,如果你需要让已经自其他类型继承的类型
支持该接口提供的
功能。
@H_
301_0@ 避免使用记号接口(没有成员)。
@H_
301_0@ 要为接口提供至少一个实现该接口的类型。
@H_
301_0@ 要为你定义的每个接口提供至少一个使用该接口的API。
@H_
301_0@ 不要给已经发行的接口再
添加成员。
@H_
301_0@ 4.7结构的设计
@H_
301_0@ 不要为结构提供默认的构造
函数。
@H_
301_0@ 要确保当所有的实例数据都为0,false,null时,结构仍处于有效状态。
@H_
301_0@ 要为值类型实现IEquatable<T>。
@H_
301_0@ 不要
显示的扩展System.ValueType,事实上多数编程语言不允许这样做。
@H_
301_0@ 4.8枚举的设计
@H_
301_0@ 要用枚举来加强那些表示值的集合的参数、
属性以及返回值的类型性。
@H_
301_0@ 要优先使用枚举而不是使用静态常量。
@H_
301_0@ 不要把枚举用于开放的集合。
@H_
301_0@ 不要提供为了今后使用而保留的
枚举值。
@H_
301_0@ 避免
显示的暴露只有一个值的枚举。
@H_
301_0@ 不要把sentinel值包含在
枚举值中。
@H_
301_0@ 要为简单枚举类型提供零值。
@H_
301_0@ 考虑用Int32作为基本的枚举实现类型,除非某一条成立:
标记枚举超过32个
标记;为了更方便的与需要不同大小的枚举的非托管
代码进行互操作,基本的实现类型必须是Int32之外的类型;更小的底层实现类型可能会节省相当的空间。
@H_
301_0@ 要用复数名词或名词短语来命名
标记枚举,单数名词或短语来命名简单枚举。
@H_
301_0@ 不要直接扩充System.Enum
@H_
301_0@ 4.8.1
标记枚举的设计
@H_
301_0@ 要对
标记枚举使用System.FlagsAttribute。
@H_
301_0@ 要用2的幂次方作为
标记枚举的值。
@H_
301_0@ 考虑为常用的
标记集合提供特殊的
枚举值。
@H_
301_0@ 避免让创建的
标记枚举包含无效的组合。
@H_
301_0@ 避免把0用作
标记枚举的值,除非该值表示所有
标记都被清除并且正确命名。
@H_
301_0@ 要把
标记枚举的0值命名为None。
@H_
301_0@ 4.8.2给枚举
添加值
@H_
301_0@ 考虑给枚举
添加值,尽管可能有一点兼容性的风险。
@H_
301_0@ 4.9嵌套类型
@H_
301_0@ 要在想让一个类型能够访问外层类型的成员时才使用嵌套类型。
@H_
301_0@ 不要用嵌套类型来进行逻辑分组,而应该用命名空间。
@H_
301_0@ 避免公开的暴露嵌套类型。
@H_
301_0@ 不要使用嵌套类型,如果该类型可能会被除了他的外层类型之外的类型引用。
@H_
301_0@ 不要使用嵌套类型,如果他们需要被客户
代码实例化。
@H_
301_0@ 不要把嵌套类型定义为接口的成员。
@H_
301_0@
@H_
301_0@ 第五章成员设计
@H_
301_0@ 5.1成员设计的一般规范
@H_
301_0@ 5.1.1成员重载
@H_
301_0@ 要尽量用描述性的参数名来说明在较短的重载中所使用的默认值。
@H_
301_0@ 避免在重载中随意的给参数命名。
@H_
301_0@ 避免使重载成员的参数顺序不一致。
@H_
301_0@ 要把最长的重载做成虚
函数(如果需要可扩展性)。
@H_
301_0@ 不要在重载成员中使用ref或out修饰符。
@H_
301_0@ 要允许可选参数为null。
@H_
301_0@ 要优先使用成员重载,而不是定义有默认参数的成员。
@H_
301_0@ 5.1.2显式的实现接口成员
@H_
301_0@ 避免显式的实现接口成员,如果没有很强的理由。
@H_
301_0@ 考虑显式的实现接口成员,如果希望接口成员只能通过该接口来
调用。
@H_
301_0@ 考虑通过显式的实现接口成员来模拟variance(在被覆盖的成员中改变参数或返回值的类型)。
@H_
301_0@ 考虑在需要隐藏一个成员并
增加一个名字更加合适的等价成员时,显式的实现接口成员。
@H_
301_0@ 不要把接口成员的显式实现用作安全壁垒。
@H_
301_0@ 要为显式实现的接口成员提供一个
功能相同的受保护的虚成员,如果希望让派生类对该
功能进行定制。
@H_
301_0@ 5.1.3
属性和
方法之间的选择
@H_
301_0@ 考虑使用
属性,如果该成员表示类型的逻辑attribute。
@H_
301_0@ 要使用
属性而不要使用
方法——如果
属性的值存储在内存中,而且提供
属性的目的仅是为了访问该值。
@H_
301_0@ 要在下列情况使用
方法而不是
属性:该操作比字段访问要慢一个或多个
数量级;该操作是一个转换操作;该操作每次返回的结果不同,即使传入的参数不变;该操作有严重的能观察到的副作用;该操作返回内部状态的一个副本;该操作返回一个数组;
@H_
301_0@ 5.2
属性的设计
@H_
301_0@ 要创建只读
属性,如果不应该让
调用方改变
属性的值。
@H_
301_0@ 不要提供只写
属性,也不要让设置
方法的存取范围比
获取方法更广。
@H_
301_0@ 要为所有的
属性提供合理的默认值。
@H_
301_0@ 要允许
用户以任何顺序来设
属性的值,尽管这可能会使对象在短时间内处于无效状态。
@H_
301_0@ 要保留
属性原来的值,如果
属性的设置
方法抛出异常。
@H_
301_0@ 避免在
属性的
获取方法中抛出异常。
@H_
301_0@ 5.2.1索引
属性的设计
@H_
301_0@ 考虑通过索引器的方式让
用户访问存储在内部数组中的数据。
@H_
301_0@ 考虑为代表项集的类型提供索引器。
@H_
301_0@ 避免有一个以上参数的索引器。
@H_
301_0@ 避免用Int32,Int64,String,Object,枚举,泛型以外的类型来作索引器的参数。
@H_
301_0@ 要用Item来作索引
属性的名字,除非有更合适的名字。
@H_
301_0@ 不要同时提供语义上等价的索引器和
方法。
@H_
301_0@ 不要在一个类型中提供具有不通名字的索引器。
@H_
301_0@ 不要使用非默认的索引
属性。
@H_
301_0@ 5.2.2
属性改变的
通知事件
@H_
301_0@ 考虑在高层API的
属性值被
修改时触发
属性改变的
通知事件。
@H_
301_0@ 考虑在
属性值被外界
修改时触发
通知事件。
@H_
301_0@ 5.3构造
函数的设计
@H_
301_0@ 考虑提供简单的构造
函数,最好是默认构造
函数。
@H_
301_0@ 考虑用静态的工厂
方法来代替构造
函数——如果无法让想要执行的操作的语义与新实例的构造
函数直接对应,或遵循构造
函数的设计规范会感觉不自然。
@H_
301_0@ 要把构造
函数的参数用作设置主要
属性的便捷
方法。
@H_
301_0@ 要使用相同的名字命名构造
函数参数和
属性,如果参数用于简单设置
属性。
@H_
301_0@ 要在构造
函数中做最少的工作。
@H_
301_0@ 要从实例构造
函数中抛出异常,如果合适。
@H_
301_0@ 要在类中显式的声明公用默认构造
函数,如果这样的构造
函数是必须的。
@H_
301_0@ 避免在结构中显式的定义默认构造
函数。
@H_
301_0@ 避免在对象的构造
函数内部
调用虚成员。
@H_
301_0@ 要把静态构造
函数声明为私有。
@H_
301_0@ 不要在静态构造
函数中抛出异常。
@H_
301_0@ 考虑以内联得形式来初始化静态字段,而不要显式的定义静态构造
函数,这是因为运行库能够对那些没有显式定义静态构造
函数的类型进行
性能优化。
@H_
301_0@ 5.4事件的设计
@H_
301_0@ 要在事件中使用术语raise,而不要使用fire或trigger。
@H_
301_0@ 要用EventHandler<T>来定义事件处理
函数,不要手工创建新的委托。
@H_
301_0@ 考虑用EventArgs的子类来做事件的参数,除非百分之百相信不需要给事件处理
方法传递数据,可以直接使用EventArgs。
@H_
301_0@ 要用受保护的虚
函数来触发事件。这只适用于非密封类中的非静态事件,不适用于结构、密封类及静态事件。
方法的名字以On开头。
@H_
301_0@ 要让触发事件的受保护
方法带一个参数,该参数的类型为事件参数类,名字为e。
@H_
301_0@ 不要在触发非静态事件时把null作为sender参数传入。
@H_
301_0@ 不要在触发事件时把null作为数据参数传入。
@H_
301_0@ 考虑触发能够被最终
用户取消的事件,这只适用于前置事件。
@H_
301_0@ 5.4.1
自定义事件处理
函数的设计
@H_
301_0@ 要把事件处理
函数的返回类型定义为void。
@H_
301_0@ 要用object作为事件处理
函数的第一个参数的类型,并命名为sender。
@H_
301_0@ 要用EventArgs或其子类作为事件处理
函数的第二个参数的类型,并命名为e。
@H_
301_0@ 不要在事件处理
函数中定义两个以上的参数。
@H_
301_0@ 5.5字段的设计
@H_
301_0@ 不要提供公有的或受保护的实例字段。
@H_
301_0@ 要用常量字段来表示永远不会改变的常量。
@H_
301_0@ 要用公有的静态只读字段来定义预定义的对象实例。
@H_
301_0@ 不要把可变类型的实例赋给只读字段。
@H_
301_0@ 5.6操作符重载
@H_
301_0@ 避免定义操作符重载,除非该类型看起来应该像个基本类型。
@H_
301_0@ 考虑在看起来应该象基本类型的类型中定义操作符重载。
@H_
301_0@ 要为表示数值的结构定义操作符重载。
@H_
301_0@ 不要在定义操作符重载时耍小聪明。
@H_
301_0@ 不要提供操作符重载,除非至少有一个操作数的类型就是定义该重载的类型。
@H_
301_0@ 要以对称的方式来重载操作符。
@H_
301_0@ 考虑为每个重载过的操作符提供对应的
方法,并用容易理解的名字命名。
@H_
301_0@ 5.6.1重载operator==
@H_
301_0@ 5.6.2类型转换操作符
@H_
301_0@ 不要提供类型转换操作符,如果没有明确的
用户需求。
@H_
301_0@ 不要定义位于类型的领域之外的类型转换操作符。
@H_
301_0@ 不要提供隐式类型转换操作符,如果该类型转换可能会丢失精度。
@H_
301_0@ 不要在隐式的类型转换中抛出异常。
@H_
301_0@ 要抛出InvalidCastException,如果类型转换会丢失精度而该操作符承诺不丢失精度。
@H_
301_0@ 5.7参数的设计
@H_
301_0@ 要用类层次结构中最接近基类的类型来作为参数的类型,同时要保证该类型能提供成员所需的
功能。
@H_
301_0@ 不要使用保留参数。
@H_
301_0@ 不要把指针、指针数组、多维数组作为公有
方法的参数。
@H_
301_0@ 要把所有的
输出参数放在所有以值和引用方式传递的参数(不
包括参数数组)后面,即使会导致重载成员参数顺序不一致。
@H_
301_0@ 要在重载成员或实现接口成员时保持参数命名一致。
@H_
301_0@ 5.7.1枚举和布尔参数之间的选择
@H_
301_0@ 要用枚举,如果不这样做会导致参数中有两个以上的布尔类型。
@H_
301_0@ 不要使用布尔参数,除非百分之百确定绝对不需要两个以上的值。
@H_
301_0@ 考虑在构造
函数中,对确实只要两种状态值的参数以及用来初始化布尔类型
属性的参数使用布尔类型。
@H_
301_0@ 5.7.2参数的验证
@H_
301_0@ 要验证传给公有的、受保护的或显式实现的成员的参数。如果验证失败,抛出ArgumentException或子类。
@H_
301_0@ 要抛出ArgumentNullException,如果传入null而该成员
不支持null。
@H_
301_0@ 要验证枚举参数。
@H_
301_0@ 不用用Enum.IsDefined来检查枚举的范围。
@H_
301_0@ 要清楚的知道传入的可变参数可能会在验证后发生改变。
@H_
301_0@ 5.7.3参数的传递
@H_
301_0@ 避免使用
输出参数或引用参数。
@H_
301_0@ 不要以引用方式传递引用类型。
@H_
301_0@ 5.7.4参数
数量可变的成员
@H_
301_0@ 考虑给数组参数
增加params关键字,如果预计
用户会传入为数不多的数组元素。
@H_
301_0@ 避免使用params数组参数,如果
调用方几乎总是有现成的数组作为输入。
@H_
301_0@ 不要使用params数组参数,如果数组会被以其为参数的成员
修改。
@H_
301_0@ 考虑在简单的重载中使用params关键字,尽管更复杂的重载不能用params。
@H_
301_0@ 要对参数进行合理的排序,以便使用params关键字。
@H_
301_0@ 考虑在对
性能要求非常高的API中为参数
数量较少的
调用提供特殊的重载和相应的实现。
@H_
301_0@ 要注意传入的params数组参数可能是null。
@H_
301_0@ 不要使用varargs
方法又称省略号。
@H_
301_0@ 5.7.5指针参数
@H_
301_0@ 要为任何以指针为参数的成员提供一个替补成员,因为指针不符合CLS规范。
@H_
301_0@ 避免对指针参数进行高开销的检查。
@H_
301_0@ 要在设计用到指针的成员时遵循与指针相关的常用约定。
@H_
301_0@
@H_
301_0@ 第6章为扩展性而设计
@H_
301_0@ 6.1扩展机制
@H_
301_0@ 6.1.1非密封类
@H_
301_0@ 考虑用不
包括任何虚成员和保护成员的非密封类来为框架提供扩展性,这种
方法开销不高。
@H_
301_0@ 6.1.2保护成员
@H_
301_0@ 考虑将保护成员用于高级定制。
@H_
301_0@ 要在对安全性、文档及兼容性进行分析时,把非密封类中保护成员当成公有成员对待。
@H_
301_0@ 6.1.3事件与回调
函数
@H_
301_0@ 考虑使用回调
函数来让框架能够执行
用户提供的
代码。
@H_
301_0@ 考虑使用事件来让
用户定制框架的行为,这样不需
用户对面向对象有深入理解。
@H_
301_0@ 要优先使用事件,而不是简单的回调
函数,原因是开发人员更熟悉事件。
@H_
301_0@ 避免在对
性能要求很高的API中使用回调
函数。
@H_
301_0@ 要理解在
调用委托时可以执行任何
代码,这可能会引起安全性、正确性、兼容性问题。
@H_
301_0@ 6.1.4虚成员
@H_
301_0@ 不要使用虚成员,除非有合适的理由,同时你对设计、测试、维护虚成员的开销有清楚的认识。
@H_
301_0@ 考虑只有在绝对必须的时候才用虚成员提供扩展性,并采用Template Method模式。
@H_
301_0@ 要优先使用受保护的虚成员,而不是公有虚成员。
@H_
301_0@ 6.1.5抽象(抽象类型和抽象接口)
@H_
301_0@ 不要提供抽象,除非为该抽象开发出具体实现并用API对其进行过实际测试。
@H_
301_0@ 要在设计抽象时谨慎的选择抽象类或是抽象接口。
@H_
301_0@ 考虑为抽象的具体实现提供参考测试。
@H_
301_0@ 6.2基类
@H_
301_0@ 考虑使基类为抽象类,即使他们不包含任何抽象成员。
@H_
301_0@ 考虑把基类与用于主要场景的类型分开,放到单独的名字空间中。
@H_
301_0@ 避免在命名基类时使用Base后缀,如果该类会用于公用API。
@H_
301_0@ 6.3密封
@H_
301_0@ 不要把类密封起来,除非有恰当的理由。
@H_
301_0@ 不要在密封类中声明保护成员或虚
函数。
@H_
301_0@ 考虑在覆盖成员时将其密封。
@H_
301_0@ 第7章异常
@H_
301_0@ 7.1抛出异常
@H_
301_0@ 不要返回
错误码。
@H_
301_0@ 要通过抛出异常的方式来报告操作失败。
@H_
301_0@ 考虑通过
调用Environment.FailFase来结束进程,而不要抛出异常,如果
代码遇到严重问题,已经无法安全的执行。
@H_
301_0@ 不要在正常的控制流中使用异常,如果可以避免的话。
@H_
301_0@ 考虑抛出异常可能会对
性能造成的影响。
@H_
301_0@ 要为所有的异常撰写文档,并把他们作为协定的一部分,前提是这些异常是由于违反了公有成员的协定而抛出的。
@H_
301_0@ 不要让公有成员根据某个选项来决定是否抛出异常。
@H_
301_0@ 不要把异常用作公有成员的返回值或
输出参数。
@H_
301_0@ 考虑使用辅助
方法来创建异常。
@H_
301_0@ 不要在异常筛选器中抛出异常。
@H_
301_0@ 避免显式的从finally块中抛出异常。
@H_
301_0@ 7.2为抛出的异常选择合适的类型
@H_
301_0@ 考虑优先使用已有的异常,而不是创建新的异常类型。
@H_
301_0@ 要使用
自定义的异常类型,如果对
错误的处理方式与其他已存在的异常类型不同。
@H_
301_0@ 不要仅仅为了拥有自己的异常而创建并使用新的异常。
@H_
301_0@ 要使用最合理、最具针对性的异常。
@H_
301_0@ 7.2.1
错误消息的设计
@H_
301_0@ 要在抛出异常时为开发人员提供丰富而有意义的
错误消息。
@H_
301_0@ 要确保异常消息的语法正确无误。
@H_
301_0@ 要确保异常消息中的每个句子都有句号。
@H_
301_0@ 避免在异常消息中使用问号和惊叹号。
@H_
301_0@ 不要在没有得到许可的情况下在异常消息中泄漏安全信息。
@H_
301_0@ 考虑把组件抛出的异常消息本地化,如果希望组件为不同国家开发人员使用。
@H_
301_0@ 7.2.2异常处理
@H_
301_0@ 不要在框架的
代码中,在捕获具体类型不确定的异常时,把
错误吞了。
@H_
301_0@ 避免在应用程序的
代码中,在捕获具体类型不确定的异常时,把
错误吞了。
@H_
301_0@ 不要在为了转移异常而编写的catch
代码块中把任何特殊的异常排除在外。
@H_
301_0@ 考虑捕获特定类型的异常,如果理解该异常产生的原因并可以作出适当的反应。
@H_
301_0@ 不要捕获不应该捕获的异常。
@H_
301_0@ 要在进行清理工作时使用try-finally,避免使用try-catch。
@H_
301_0@ 要在捕获并重新抛出异常时使用空的throw语句。
@H_
301_0@ 不要用无参数的catch块来处理不符合CLS规范的异常。
@H_
301_0@ 7.2.3对异常进行封装
@H_
301_0@ 考虑对较低层次抛出的异常进行适当的封装,如果较低层次的异常在较高层次的运行环境中没有什么实际的意义。
@H_
301_0@ 避免捕获并封装具体类型不确定的异常。
@H_
301_0@ 要在对异常进行封装时为其指定内部异常。
@H_
301_0@ 7.3标准异常类型的使用
@H_
301_0@ 7.3.1Exception与SystemException
@H_
301_0@ 不要抛出Exception和SystemException异常。
@H_
301_0@ 不要打算在框架
代码中捕获这两种异常,除非打算重新抛出。
@H_
301_0@ 避免捕获这两种异常,除非是在顶层异常处理器中。
@H_
301_0@ 7.3.2ApplicationException
@H_
301_0@ 不要抛出ApplicationException或从他派生新类。
@H_
301_0@ 7.3.3InvalidOperationException
@H_
301_0@ 要抛出InvalidOperationException异常,如果对象处于不正确的状态。
@H_
301_0@ 7.3.4ArgumentException,ArgumentNullException,ArgumentOutOfRangeException
@H_
301_0@ 要抛出ArgumentException或其子类,如果传入的是无效参数。
@H_
301_0@ 要在抛出ArgumentException或其子类异常时设置ParamName
属性。
@H_
301_0@ 要在
属性的设置
方法中,以value作为隐式值参数的名字。
@H_
301_0@ 7.3.5NullReference,IndexOutOfRange,AccessViolation
@H_
301_0@ 不要让公用API显式的或隐式的抛出这几个异常。
@H_
301_0@ 7.3.6StackOverflow
@H_
301_0@ 不要显式的抛出StackOverflow异常。
@H_
301_0@ 不要捕获StackOverflow异常。
@H_
301_0@ 7.3.7OutOfMemory
@H_
301_0@ 不要显式的抛出OutOfMemory异常。
@H_
301_0@ 7.3.8ComException,SEHException及其他CLR异常
@H_
301_0@ 不要显式的抛出Interop,Com,SEH异常。
@H_
301_0@ 不要显式的捕获SHE异常。
@H_
301_0@ 7.3.9ExecutionEngine
@H_
301_0@ 不要显式的抛出ExecutionEngine异常。
@H_
301_0@ 7.4
自定义异常的设计
@H_
301_0@ 避免太深的继承层次。
@H_
301_0@ 要从Exception或其他常用基类派生新的异常类。
@H_
301_0@ 要在命名异常类时使用Exception后缀。
@H_
301_0@ 要使异常可序列化。
@H_
301_0@ 要为所有的异常提供常用的构造
函数。
@H_
301_0@ 要通过ToString的重载
方法报告对安全敏感的信息,前提是必须获得相应的许可。
@H_
301_0@ 要把与安全性有关的信息保存在私有的异常状态中。
@H_
301_0@ 考虑为异常定义
属性,这样就能从程序中取得异常的额外信息。
@H_
301_0@ 7.5异常与
性能
@H_
301_0@ 不要因异常可能对
性能造成的负面影响而使用
错误码。
@H_
301_0@ 7.5.1Tester-Doer模式
@H_
301_0@ 考虑在
方法中使用Tester-Doer模式来避免因异常而引起的
性能问题,如果该
方法在普通的场景中都可能会抛出异常。(可能会引起竞态条件,使用须小心)
@H_
301_0@ 7.5.2Try-Parse模式
@H_
301_0@ 考虑在
方法中使用Try-Parse模式来避免因异常而引起的
性能问题,如果该
方法在普通的场景中都可能会抛出异常。
@H_
301_0@ 要在实现Try-Parse模式时使用Try前缀,并用布尔作为该
方法的返回类型。
@H_
301_0@ 要为每个使用Try-Parse模式的
方法提供一个会抛出异常的对应成员。
@H_
301_0@
@H_
301_0@ 第8章使用规范
@H_
301_0@ 8.1数组
@H_
301_0@ 要在公用API中优先使用集合,而不是数组。
@H_
301_0@ 不要使用只读的数组字段。
@H_
301_0@ 考虑使用不规则数组,而不要使用多维数组。
@H_
301_0@ 8.2Attribute
@H_
301_0@ 要在命名
自定义attribute类时
添加Attribute后缀。
@H_
301_0@ 要在定义自己的attribute时使用AttributeUsageAttribute。
@H_
301_0@ 要为可选参数提供可设置的
属性。
@H_
301_0@ 要为必填参数提供只读
属性。
@H_
301_0@ 要提供构造
函数参数来对必填参数进行初始化。每个参数名和
属性名相同。
@H_
301_0@ 避免提供构造
函数参数来对可选参数进行初始化。
@H_
301_0@ 避免对
自定义attribute的构造
函数进行重载。
@H_
301_0@ 要尽可能将
自定义attribute类封装起来。
@H_
301_0@ 8.3集合
@H_
301_0@ 不要在公用API中使用弱类型集合。
@H_
301_0@ 不要在公用API中使用ArrayList或List<T>。
@H_
301_0@ 不要在公用API中使用Hashtable或Dictionary<TKey,TValue>。应使用IDictionary。
@H_
301_0@ 不要使用IEnumerator<T>,IEnumerator或实现两个接口之一的任何类型,除非是作为GetEnumerator
方法的返回值。
@H_
301_0@ 不要在一个类型中同时实现IEnumerator<T>,IEnumerable<T>。对非泛型接口同样适用。
@H_
301_0@ 8.3.1集合参数
@H_
301_0@ 要用最泛的类型作为参数类型。大多数使用IEnumerable<T>接口。
@H_
301_0@ 避免使用ICollection<T>或ICollection来做参数,如果其目的仅是为了访问接口的Count
属性。
@H_
301_0@ 8.3.2集合
属性与返回值
@H_
301_0@ 不要提供可设置的集合
属性。
@H_
301_0@ 要用Collection<T>或其子类作为
属性或返回值来表示可读写的集合。
@H_
301_0@ 要用ReadOnlyCollection<T>或其子类作为
属性或返回值来表示只读的集合。
@H_
301_0@ 考虑使用泛型集合基类的子类,而不要直接使用该集合。
@H_
301_0@ 要用Collection<T>,ReadOnlyCollection<T>的子类作为常用
方法和
属性的返回值。
@H_
301_0@ 考虑使用有键集合,如果集合中存储的元素都有独一无二的键值。
@H_
301_0@ 不要从集合
属性或以集合为返回值的
方法中返回null。可返回一个空集合。
@H_
301_0@ 1SnapshotCollection与LiveCollection
@H_
301_0@ 不要让
属性返回SnapshotCollection,
属性应返回LiveCollection。
@H_
301_0@ 要用SnapshotCollection或Live IEnumerable<T>表示不稳定的集合。
@H_
301_0@ 8.3.3数组和集合之间的选择
@H_
301_0@ 要优先使用集合,而不是数组。
@H_
301_0@ 考虑在低层API中使用数组,以降低内存的消耗提高
性能。
@H_
301_0@ 要使用字节数组,而不要使用字节集合。
@H_
301_0@ 不要将数组用于
属性,如果每次
调用属性的
获取方法时都必须返回一个新数组。
@H_
301_0@ 8.3.4
自定义集合的实现
@H_
301_0@ 不要继承自非泛型的集合基类。
@H_
301_0@ 要为强类型的非泛型集合实现IEnumerable<T>。
@H_
301_0@ 避免为类型实现集合接口,如果类型的API很复杂,而且与集合的概念无关。
@H_
301_0@ 要在为实现IEnumerable<T>接口的类型命名时
添加Collection后缀,除非同时实现IDictionary或IDictionary<TKey,TValue>。
@H_
301_0@ 要在为实现IDictionary或IDictionary<TKey,TValue>的类型命名时
添加Dictionary后缀。
@H_
301_0@ 避免给集合抽象的名字
添加代表具体实现的后缀。
@H_
301_0@ 考虑用集合元素的类型名作为集合名字的前缀。
@H_
301_0@ 考虑给只读集合的名字
添加ReadOnly前缀。
@H_
301_0@ 8.4ICloneable
@H_
301_0@ 不要实现ICloneable。
@H_
301_0@ 不要在公用API中使用ICloneable。
@H_
301_0@ 考虑为需要运用克隆机制的类型定义Clone
方法。
@H_
301_0@ 8.5IComparable<T>与IEquatable<T>
@H_
301_0@ 要为值类型实现IEquatable<T>。
@H_
301_0@ 要在实现IEquatable<T>.Equals
方法时,遵循覆盖Object.Equals
方法的规范。
@H_
301_0@ 要在实现IEquatable<T>.Equals
方法的同时覆盖Object.Equals。
@H_
301_0@ 考虑在实现IEquatable<T>的同时重载operator==和!=。
@H_
301_0@ 要在实现IComparable<T>的同时实现IEquatable<T>。
@H_
301_0@ 考虑在实现IComparable<T>的同时重载比较操作符<><= >=。
@H_
301_0@ 8.6IDisposable
@H_
301_0@ 8.7对象
@H_
301_0@ 8.7.1Object.Equals
@H_
301_0@ 要在覆盖Object.Equals时,遵循他定义的协定。
@H_
301_0@ 要在覆盖Equals
方法的同时,覆盖GetHashCode
方法。
@H_
301_0@ 考虑在覆盖Object.Equals的同时实现IEquatable<T>接口。
@H_
301_0@ 不要从Equals
方法中抛出异常。
@H_
301_0@ 1值类型的Equals
@H_
301_0@ 要覆盖值类型的Equals
方法。
@H_
301_0@ 要通过实现IEquatable<T>来提供一个以值类型本身为参数的Equals重载
方法。
@H_
301_0@ 2引用类型的Equals
@H_
301_0@ 考虑对Equals进行覆盖以提供值相等语义,如果引用类型表示的是一个值。
@H_
301_0@ 8.7.2Object.GetHashCode
@H_
301_0@ 要覆盖GetHashCode
方法,如果覆盖了Object.Equals
方法。
@H_
301_0@ 要确保对任何两个对象来说,如果Object.Equals
方法返回true,GetHashCode返回值也相同。
@H_
301_0@ 要尽量让类型的GetHashCode
方法产生
随机分布的散列码。
@H_
301_0@ 要确保无论怎么更改对象,GetHashCode都会返回万全相同的值。
@H_
301_0@ 避免从GetHashCode中抛出异常。
@H_
301_0@ 8.7.3Object.ToString
@H_
301_0@ 要覆盖ToString
方法,只有返回既有用又易于阅读的
文字。
@H_
301_0@ 要尽量让ToString
方法返回短小的字符串。
@H_
301_0@ 考虑为每一个实例返回一个独一无二的字符串。
@H_
301_0@ 要使用易于阅读的名字,不要为了独一无二使用难以阅读的ID。
@H_
301_0@ 要在返回与culture有关的信息时,根据当前线程的culture对字符串格式化。
@H_
301_0@ 要提供重载
方法ToString(string format)或实现IFormattable接口。
@H_
301_0@ 不要从ToString
方法返回空字符串或null。
@H_
301_0@ 避免从ToString
方法抛出异常。
@H_
301_0@ 要确保ToString
方法不会产生副作用。
@H_
301_0@ 要通过覆盖ToString报告对安全敏感的信息,前提是获得许可。
@H_
301_0@ 考虑让ToString
方法输出的字符串能够为该类型的解析
方法正确的解析。
@H_
301_0@ 8.8Uri
@H_
301_0@ 要使用Uri表示URI和URL的数据。
@H_
301_0@ 考虑为最常用的带Uri参数的成员提供基于字符串的重载成员。
@H_
301_0@ 不要为所有基于Uri的成员提供基于字符产的重载成员。
@H_
301_0@ 要
调用基于Uri的重载成员,如果有的话。
@H_
301_0@ 不要在字符串中存储URI/URL数据。
@H_
301_0@ 8.9Xml的使用
@H_
301_0@ 不要用XmlNode或XmlDocument来表示xml数据。要用IXPathNavigable来代替。
@H_
301_0@ 要用XmlReader作为
方法的xml数据输入,或用IXPathNavigable作为
方法返回的xml。
@H_
301_0@ 要为类型实现IXPathNavigable接口,如果该类型表示下层对象模型或数据源的xml视图。
@H_
301_0@ 不要从XmlDocumeng派生子类,如果该类型表示下层对象模型或数据源的xml视图。
@H_
301_0@ 8.10相等性操作符
@H_
301_0@ 不要只重载相等性操作符中的一个。
@H_
301_0@ 要确保Object.Equals与相等性操作符具有万全相同的语义和相近的
性能。
@H_
301_0@ 避免从相等性操作符中抛出异常。
@H_
301_0@ 8.10.1值类型的相等性操作符
@H_
301_0@ 要重载值类型的相等性操作符,如果相等性是有意义的。
@H_
301_0@ 8.10.2引用类型的相等性操作符
@H_
301_0@ 避免重载可变引用类型的相等性操作符。
@H_
301_0@ 考虑不要重载引用类型的相等性操作符,即使覆盖了Object.Equals或实现了IEquatable<T>。
@H_
301_0@ 避免重载引用类型的相等性操作符,如果其实现回比引用相等性慢的多。
@H_
301_0@
@H_
301_0@ 第9章常用的设计模式
@H_
301_0@ 9.1聚合组件
@H_
301_0@ 把多个低层类型集中到一个高层类型中,以次来
支持常用场景。
@H_
301_0@ 9.1.1面向组件的设计
@H_
301_0@ 聚合组件是一个façade,他基于面向组件的设计,并满足:
@H_
301_0@ 构造
函数:聚合组件应该有默认构造
函数。
@H_
301_0@ 构造
函数:构造
函数的所有参数应该与
属性对应,并用来初始化
属性。
@H_
301_0@
属性:大多数
属性应该有
获取方法和设置
方法。
@H_
301_0@
属性:所有
属性都有合理的默认值。
@H_
301_0@
方法:如果参数在
方法调用之间不会改变,那么
方法就不应该带这样的参数。这样的选项应该通过
属性指定。
@H_
301_0@ 事件:
方法不以委托为参数。所有回调
函数都通过事件实现。
@H_
301_0@ 9.1.2因子类型
@H_
301_0@ 9.1.3聚合组件规范
@H_
301_0@ 考虑为常用的特性域提供聚合组件。
@H_
301_0@ 要用聚合组件来为高层的概念(物理实体),而不是系统级的任务建模。
@H_
301_0@ 要让聚合组件的名字与众所周知的系统实体相对应,使类型更引人注目。
@H_
301_0@ 要在设计聚合组件时使初始化尽可能简单,只需简单初始化就可使用。
@H_
301_0@ 不要要求聚合组件的
用户在简单场景中显式的实例化多个对象。
@H_
301_0@ 要保证让聚合组件
支持Create-Set-Call使用方式,以此实现大多数场景。
@H_
301_0@ 要为所有聚合组件提供默认构造
函数或非常简单的构造
函数。
@H_
301_0@ 要为聚合组件提供带
获取方法和设置
方法的
属性,来对应构造
函数中的所有参数。
@H_
301_0@ 要在聚合组件中使用事件,而不用使用基于委托的API。
@H_
301_0@ 考虑用事件来代替需要被覆盖的虚成员。
@H_
301_0@ 不要要求聚合组件的
用户在常用场景中使用继承、覆盖
方法或实现接口。
@H_
301_0@ 不要要求聚合组件的
用户在常用场景中除了编码之外,还要做其他工作。
@H_
301_0@ 考虑让聚合组件能够
自动切换模式。
@H_
301_0@ 不要设计有多种模式的因子类型。
@H_
301_0@ 考虑将聚合组件集成到vs设计器中。
@H_
301_0@ 考虑把聚合组件和因子类型分开,各自放到不同的程序集中。
@H_
301_0@ 考虑把聚合组件的内部因子类型暴露给外界访问。
@H_
301_0@ 9.2Async模式
@H_
301_0@ 要在为异步操作定义API时遵循如下约定:应该提供Begin和End加同步
方法名的
方法,并设置合适的参数和返回类型。
@H_
301_0@ 要确保Begin
方法的返回类型实现了IAsyncResult接口。
@H_
301_0@ 要确保同步
方法的按值传递和按引用传递的参数在Begin
方法中都是按值传递的,同步
方法的
输出参数不应该出现在Begin
方法中。
@H_
301_0@ 要确保End
方法的返回类型与同步
方法相同。
@H_
301_0@ 要确保同步
方法的
输出参数和按引用传递的参数都作为End
方法的
输出参数,同步
方法的按值传递的参数不出现在End
方法中。
@H_
301_0@ 不要继续执行异步操作,如果Begin
方法抛出了异常。
@H_
301_0@ 要依次通过如下机制告诉
调用方异步操作已经完成:将IAsyncResult.IsCompleted设为true;
调用Async回调
函数;激活IAsyncResult.AsyncWaitHandler返回的等待句柄。
@H_
301_0@ 要通过从End
方法中抛出异常来表示无法成功的完成异步操作。
@H_
301_0@ 要在End
方法被
调用时完成所有没有完成的操作。
@H_
301_0@ 考虑抛出InvalidOperationException,如果
用户用同一个IAsyncResut两次
调用End
方法,或IAsyncResult是从另一个不相关的Begin
方法返回的。
@H_
301_0@ 要把IAsyncResult.CompletedSynchronously设为true,当且仅当Async回调
函数将在
调用Begin
方法的线程中运行时。
@H_
301_0@ 9.3Dispose模式
@H_
301_0@ 要为含有可处置类型实例的类型实现基本Dispose模式。
@H_
301_0@ 要为类型实现基本Dispose模式并提供终结
方法,如果类型持有需要开发人员显式释放的类型,而且后者本身没有终结
方法。
@H_
301_0@ 考虑为类实现基本Dispose模式,如果类本身并不持有非托管资源或可处理对象,但他的子类却可能会持有。
@H_
301_0@ 9.3.1基本Dispose模式
@H_
301_0@ 要声明protected virtual void Dispose(bool disposing)
方法来把所有与非托管资源清理相关的工作放在一起。
@H_
301_0@ 要按如下步骤实现IDisposable接口,先
调用Dispose(true),再
调用GC.SuppressFinalize(this)。
@H_
301_0@ 不要使无参数的Dispose
方法为虚
方法。
@H_
301_0@ 不要为Dispose声明除Dispose()和Dispose(bool)之外的其他重载
方法。
@H_
301_0@ 要允许多次
调用Dispose(bool)
方法。他可以在第一次
调用后就什么也不做。
@H_
301_0@ 避免从Dispose(bool)中抛出异常,除非紧急情况,所处的线程被破坏。
@H_
301_0@ 要从成员中抛出ObjectDisposedException异常,如果成员在对象被dispose后就无法再使用。
@H_
301_0@ 考虑在Dispose
方法之外再提供一个Close
方法,如果Close是该领域标准术语。
@H_
301_0@ 9.3.2可终结类型
@H_
301_0@ 避免使类型为可终结。
@H_
301_0@ 不要使值类型为可终结。
@H_
301_0@ 要使类型为可终结,如果类型要负责释放本身并不具备终结
方法的非托管资源。
@H_
301_0@ 要为所有的可终结类型实现基本Dispose模式。
@H_
301_0@ 不要在终结
方法调用的
代码中访问任何可终结对象。
@H_
301_0@ 要使Finalize
方法为受保护的。
@H_
301_0@ 不要在终结
方法中放过任何异常,除非是致命的系统
错误。
@H_
301_0@ 考虑创建一个用于紧急情况的可终结对象,如果应用程序域被强制卸出或线程异常
退出时都必须执行终结
方法。
@H_
301_0@ 9.4Factory模式
@H_
301_0@ 要优先使用构造
函数,而不是优先使用工厂,构造
函数一般来说更易于使用,更一致,更方便。
@H_
301_0@ 考虑使用工厂,如果构造
函数提供的
对象创建机制不能实现要求。
@H_
301_0@ 要在开发人员可能不清楚待创建对象的类型时使用工厂,比如对基类或接口编程。
@H_
301_0@ 考虑使用工厂
方法,如果这是唯一的办法使其对
用户来说不解自明。
@H_
301_0@ 要在转换风格的操作中使用factory。
@H_
301_0@ 要尽量将工厂操作实现为
方法,而不是
属性。
@H_
301_0@ 要通过
方法的返回值而不是
输出参数来返回新创建的对象实例。
@H_
301_0@ 考虑把create和要创建的对象类型名连在一起,以此来命名工厂
方法。
@H_
301_0@ 考虑把要创建的类型名和factory连在一起,来命名工厂类型。
@H_
301_0@ 9.5Optional Feature模式
@H_
301_0@ 考虑将Optional Feature模式用于抽象中的可选特性。
@H_
301_0@ 要提供一个简单的布尔
属性,
用户能够用他来检查对象是否
支持可选特性。
@H_
301_0@ 要在基类中用虚
方法来定义可选特性,并抛出NotSupported异常。
@H_
301_0@ 9.6Template Method模式
@H_
301_0@ 最常见的形式有一或多个非虚成员组成,这些成员通过
调用一或多个受保护的虚成员实现。
@H_
301_0@ 避免使公有成员为虚成员。
@H_
301_0@ 考虑使用Template Method模式来更好的控制扩展性。
@H_
301_0@ 考虑将受保护的虚成员命名为非虚成员加Core后缀,如果虚成员为非虚成员提供了扩展点。
@H_
301_0@ 9.7超时
@H_
301_0@ 要优先让
用户通过参数来提供超时长度。
@H_
301_0@ 要优先使用TimeSpan来表示超时长度。
@H_
301_0@ 要在超时后抛出TimeoutException异常。
@H_
301_0@ 不要通过返回
错误码的方式来告诉
用户发生了超时。
@H_
301_0@
@H_
301_0@ A C#编程风格约定
@H_
301_0@ 1通用风格约定
@H_
301_0@ 1.1花括号的使用
@H_
301_0@ 要把左花括号放在前一条语句的末尾。
@H_
301_0@ 要使右括号与左括号所在行的行首对齐,除非括号内只有一条语句。
@H_
301_0@ 要把右括号放在新的一行的开始处。
@H_
301_0@ 考虑把只有一条语句的
代码块和括号放在一行中。
@H_
301_0@ 考虑只有一个访问
方法的
属性的所有花括号放在同一行中。
@H_
301_0@ 要使右花括号单独占一行,除非后面是else,else if或while。
@H_
301_0@ 避免省略花括号。
@H_
301_0@ 1.2空格的使用
@H_
301_0@ 要在左花括号后和右花括号前加一个空格。
@H_
301_0@ 避免在左花括号前加空格。
@H_
301_0@ 要在形式参数的逗号后加空格。
@H_
301_0@ 避免在实际参数之间加空格。
@H_
301_0@ 避免在左圆括号之后和右圆括号之前加空格。
@H_
301_0@ 不要在成员名字和左圆括号之间加空格。
@H_
301_0@ 不要在左方括号之后和右方括号前加空格。
@H_
301_0@ 不要在控制流语句之前加空格。
@H_
301_0@ 避免在二元操作符之前和之后加空格。
@H_
301_0@ 不要在一元操作符之前或之后加空格。
@H_
301_0@ 1.3缩进的使用
@H_
301_0@ 要用4个连续空格进行缩进。
@H_
301_0@ 不要用制表符进行缩进。
@H_
301_0@ 要对
代码块中的
内容进行缩进。
@H_
301_0@ 要对case
代码块进行缩进,尽管没有花括号。
@H_
301_0@ 2命名约定
@H_
301_0@ 要在命名标识符时遵循框架设计准则,除非是内部字段和私有字段。
@H_
301_0@ 要在命名名字空间、类、成员时使用PascalCasing风格,除非内部字段和私有字段。
@H_
301_0@ 要用camelCasing风格来命名内部字段和私有字段。
@H_
301_0@ 要用camelCasing风格来命名局部变量。
@H_
301_0@ 要用camelCasing风格来命名
方法的形式参数。
@H_
301_0@ 不要使用匈牙利命名法。
@H_
301_0@ 避免给局部变量加前缀。
@H_
301_0@ 要使用C#语言中对应的别名。
@H_
301_0@ 3注释
@H_
301_0@ 不要用注释来描述对任何人都显而易见的事。
@H_
301_0@ 避免使用块注释语法。
@H_
301_0@ 不要把注释放在行尾,除非注释非常短。
@H_
301_0@ 4
文件的组织
@H_
301_0@ 不要在一个源
文件中包含一个以上的公用类型,除非有嵌套类,或各类型之间的不同仅在于泛型参数的
数量。
@H_
301_0@ 要用相同的名字命名源
文件及其包含的公有类型。
@H_
301_0@ 要用相同的层次来组织
文件目录和命名空间。
@H_
301_0@ 考虑根据如下顺序和组别对成员分组:所有字段,所有构造
函数,公用
属性及受保护的
属性,
方法,事件,所有显式实现的接口成员,内部成员,私有成员,所有嵌套类型。
@H_
301_0@ 要把不能公开访问的成员和显式实现的接口成员分别放在自己的#region块中。
@H_
301_0@ 考虑在每个组别内根据字母顺序来组织成员。
@H_
301_0@ 考虑根据由简单到复杂的顺序来组织重载成员。
@H_
301_0@ 要把using指令放到命名空间的声明之外。
@H_
301_0@ 转载地址:http://blog.csdn.net/dreamboy0908/article/details/7230549