《.NET 设计规范》第 5 章:成员设计

《.NET 设计规范》第 5 章:成员设计

5.1 成员设计的通用规范

  要尽量用描述性的参数名来说明在较短的重载中使用的默认值。

  避免在重载中随意地改变参数的名字。如果两个重载中的某个参数表示相同的输入,那么该参数的名字应该相同。

  避免使重载成员的参数顺序不一致。在所有的重载中,同名参数应该出现在相同的位置。

  要把最长的重载成员定义成重载成员中唯一的虚成员。

  不要用 ref 或 out 修饰符来对成员进行重载。

  不要定义这样的重载:位于同一个位置的参数有相似的类型但却有不同的语义。

  要允许在传递参数时将可选参数设为 null。

  要优先使用成员重载,而不是定义有默认参数的成员。

  显式地实现接口成员。

  避免显示地实现接口成员 - 如果没有很强的理由。

  考虑显式地实现接口成员 - 如果希望接口成员只能通过该接口来调用。

  考虑通过显式地实现接口成员的方式来模拟变体。

  考虑在需要隐藏一个成员并增加另一个名字更合适的等价成员时,显式地实现接口成员。

  不要把接口成员的显示实现当做安全壁垒。

  要为显式实现的接口成员提供具有相同功能的受保护的虚成员 - 如果希望让派生类对该功能进行定制。

  考虑使用属性 - 如果该成员表示类型的一种逻辑属性。

  要使用属性而不要使用方法 - 如果属性的值储存在进程内存中,而且提供属性的目的仅仅是为了访问该值。

  要在下列情况中时使用方法而不要使用属性:

    该操作比字段访问要慢几个数量级;

    该操作是一个转换操作,如:object.ToString() 方法;

    该操作在每次调用时都返回不同的结果,即使传入的参数不变。如:Guid.NewGuid 方法在每次都返回不同的值;

    该操作有严重的、显而易见的副作用;

    该操作返回内部状态的一个副本(这不包括那些在栈上返回的值类型对象的副本);

    该操作返回一个数组。

5.2 属性的设计

  要创建只读属性 - 如果调用方不应该改变属性的值。

  不要提供只写属性,也不要让 setter 的可访问性比 getter 更广。

  要为所有的属性提供合理的默认值,这样可以确保默认值不会导致安全漏洞或效率低下的代码。

  要允许用户以任何顺序来设属性的值,即使这可能会使对象在短时间内处于无效状态。

  要保留属性原来的值,如果属性的 setter 抛出异常。

  避免在属性的 getter 中抛出异常。

  考虑通过索引器的方式让用户访问存储在呢不数组中的数据。

  考虑为代表元素集合的类型提供索引器。

  避免使用有一个以上参数的索引属性。

  避免用 System.Int32、System.Int64、System.String、System.Object、枚举或泛型参数之外的类型来作索引器的参数。

  要将 Item 名称用于索引属性,除非有明显更好的名字(例如 System.String 的 Chars 属性)。

  不要同时提供语义上等价的索引器和方法。

  不要在一个类型中提供具有不同名字的索引器。

  不要使用非默认的索引属性。

  考虑在高层 API 的属性值被修改时触发属性改变的通知事件。

  考虑在属性值被外界修改时触发通知事件。

  

5.3 构造函数的设计

  考虑提供简单的构造函数,最好是默认构造函数。

  考虑用静态工厂方法来代替构造函数 - 如果无法让想要执行的操作的语义与新实例的构造函数直接对应,或者遵循构造函数的设计规范会让人感觉不合理。

  要把构造函数的参数列表当做设置主要属性的快捷方法。

  要用相同的名字来命名构造函数的参数和属性 - 如果定义该构造函数参数的目的就是为了设置对应的属性。

  要在构造函数中做最少的工作。

  要在适当的时候从实例构造函数中抛出异常。

  要在类中显式地声明公有的默认构造函数 - 如果这样的构造函数是必需的。 

  避免在结构中显式地定义默认构造函数。

  避免在对象的构造函数内部调用虚成员。

  要把静态构造函数声明为私有。

  不要从静态构造函数中抛出异常。

  考虑以内联的形式来初始化静态字段,而不要显式地定义静态构造函数,这是因为运行库能够对那些没有显示定义静态构造函数的类型进行性能优化。

5.4 事件的设计

  要在事件中使用术语“raise”,而不要使用“fire”或“trigger”。

  要用 System.EventHandler<T> 来定义事件处理函数,而不是手工创建新的委托来定义事件处理函数。

  考虑用 EventArgs 的子类来做事件的参数,除非百分之百确信该事件不需要给事件处理方法传递任何数据,在这种情况下可以直接使用 EeventArgs。

  要用受保护的虚方法来触发事件。这只适用于非密封类中的非静态事件,不适用于结构、密封类以及静态事件。

  要让触发事件的受保护的方法带一个参数,该参数的类型为事件参数类,该参数的名字应该为 e。

  不要在触发非静态事件时把 null 作为 sender 参数传入。

  要在触发静态事件时把 null 作为 sender 参数传入。

  不要在触发事件时把 null 作为数据参数传入。

  考虑触发能够被最终用户取消的事件,这适用于前置事件。

  要把事件处理函数的返回类型定义为 void。

  要用 object 作为事件处理函数的第一个参数的类型,并将其命名为 sender。

  要用 System.EventArgs 或其子类作为事件处理函数的第二个参数的类型,并将其命名为 e。

  不要在事件处理函数中使用两个以上的参数。

  

5.5 字段的设计

  不要提供公有的或受保护的实例字段。

  要用常量字段来表示永远不会改变的常量。

  要用公有的静态只读字段来定义预定义的对象实例。

  不要把可变类型的实例赋值给只读字段。

  

5.6 扩展方法

  避免草率地定义扩展方法,尤其是为别人的类型定义扩展方法。

  考虑在下面的场景中使用扩展方法。

  为一个接口的所有实现提供相关的辅助方法,而且这些功能可以通过核心接口来表达。

  如果增加一个实例方法会引入对其它类型的依赖关系,而依赖关系会破坏依赖关系的管理规则,那么应该使用扩展方法。

  避免为 System.Object 定义扩展方法。

  不要把扩展方法和被扩展的类型放在同一个命名空间中 - 除非是为了把方法增加到接口中,或是为了对依赖关系进行管理。

  避免在定义两个扩展方法时使用相同的签名,即使它们位于不同的命名空间。

  考虑把扩展方法和被扩展的类型放在同一个命名空间 - 如果被扩展的类型是接口,而且该扩展方法的设计目的就是要用于大多数的情况甚至是所有的情况。

  不要把实现某个特性的扩展方法放在一个通常与其他特性相关联的命名空间中。相反,该特性属于哪个命名空间,就应该把对应的扩展方法放在那里。

  避免使用太宽泛的名字(例如“Extensions”)来给扩展方法专用的命名空间命名,要使用更具描述性的名字(比如“Routing”)。

  

5.7 操作符重载

  避免定义操作符重载,除非该类型让人感觉像个基本(内置)类型。

  考虑在让人感觉应该想基本类型的类型中定义操作符重载。

  要为表示数值的结构(比如 System.Decimal)定义操作符重载。

  不要在定义操作符重载时耍小聪明。

  不要提供操作符重载,除非至少有一个操作数的类型是定义该操作符重载的类型。

  要以对称的方式来重载操作符。

  考虑为每个重载过的操作符提供对应的方法,并用容易理解的名字来命名。

  不要提供类型转换操作符 - 如果没有明确的用户需求。

  不要在定义类型转换操作符时超越类型所在的领域。

  不要提供隐式类型转换操作符 - 如果这样的类型转换可能会丢失精度。

  不要从隐式的强制类型转换操作符中抛出异常。

  要抛出 System.InvalidCastException - 如果对强制类型转换操作符的调用会丢失精度而该操作符承诺不丢失精度。

5.8 参数的设计

  要用类层次结构中最接近基类的类型作为参数的类型,同时要保证该类型能够提供成员所需的功能。

  不要使用保留参数。

  不要把指针、指针数组及多维数组作为公有方法的参数。

  要把所有的输出参数放在所有以值方式和以引用方式传递的参数的后面(不包括参数数组),即使这样会在重载成员之间导致参数顺序不一致也要如此。

  要在覆盖成员或者实现接口成员时保持参数命名的一致。

  要用枚举 - 如果不这样做会导致参数中有两个或两个以上的布尔类型。

  不要使用布尔参数,除非百分之百肯定绝对不需要两个以上的值。

  考虑在构造函数中,对确实只有两种状态的参数以及用来初始化布尔属性的参数使用布尔类型。

  要对传给共有的、受保护的或显式实现的成员的参数进行验证。如果验证失败,那么应该抛出 System.ArgumentException 或其子类。

  要抛出 ArgumentNullExcepytion - 如果传入的是 null 而该成员不支持 null。

  要验证枚举参数。

  不要用 Enum.IsDefined 来检查枚举的范围。

  要清楚地知道传入的可变参数可能会在验证后发生改变。

  避免使用输出参数或引用参数。

  不要以引用方式传递引用类型。

  考虑给数组参数增加 params 关键字 - 如果预计用户会传入为数不多的数组元素。

  避免使用 params 数组参数 - 如果绝大多数时候调用方要传入的数组元素本来就已经在一个数组中了。

  不要使用 params 数组参数 - 如果要在成员中对数组进行修改。

  考虑在简单的重载中使用 params 关键字,尽管更复杂的重载不能用 params 关键字。

  要对参数进行合理的排序,以便使用 params 关键字。

  考虑在对性能要求非常高的 API 中为参数数量较少的调用提供特殊的重载和相应的实现。

  要注意传入的 params 数组参数可能是 null。

  不要使用 varargs 方法,又称省略号。

  要为任何以指针为参数的成员提供一个替补成员,这是因为指针不符合 CLS 规范。

  避免对指针参数进行高开销的检查。

  要在设计用到指针的成员时遵循与指针相关的常用约定。

  

时间: 2024-08-06 03:47:03

《.NET 设计规范》第 5 章:成员设计的相关文章

NET设计规范二:类型成员设计

http://www.cnblogs.com/yangcaogui/archive/2012/04/20/2459567.html 接着 → .NET设计规范一:设计规范基础 上一篇,我们来了解下类型成员命名的设计! 3.类型成员命名的设计 3.1字段 ①遵循“ camelCasing  ”的命名规则 ②要用名词或名词词组,不要使用C#关键字 ③不要给字段添加任何前缀 ④定义常量的时候要使用“PascalCasing ”的命名规范 ⑤当定义私有变量的时候使用“camelCasing”命名,并且在

【安富莱二代示波器教程】第9章 示波器设计—自动触发和普通触发

第9章        示波器设计-自动触发和普通触发 自带触发和普通触发是示波器设计中比较重要的两个功能,本章节为大家讲解二代示波器中自动触发和普通触发的实现. 9.1    自动触发 9.2    普通触发 9.3     总结 9.1  自动触发 由于示波器模拟前端模块稍有些问题,所以自动触发功能是用软件实现的.软件实现自动触发比较容易实现,具体的实现代码如下: /* 通过软件检测实现上升沿触发,并保留最后600的数据不做检测,用于直接显示 2048-600 = 1448; */ j = 0

ASP.Net MVC 5 高级编程 第7章 成员资格、授权和安全性

第7章 成员资格.授权和安全性 7.1 安全性 ASP.NET MVC 提供了许多内置的保护机制(默认利用 HTML 辅助方法和Razor 语法进行 HTML编码以及请求验证等功能特性,以及通过基架构建的控制器白名单表单元素来防止重复提交攻击) 永远不要相信用户提交的任何数据. 实际的例子 每次渲染用户提交的数据的时候对其进行编码. 考虑好网站哪些部分允许用户匿名访问,哪些部分需要认证访问. 不要试图自己净化用户的HTML 输入,否则就会失败. 在不需要通过客户端脚本访问cookie时,使用HT

mySQL教程 第1章 数据库设计

第1章 数据库设计 E-R设计 很多同学在学SQL语句时,觉得非常困难,那是因为你在学一个你根本不了解的数据库,数据库中的表不是你设计的,表与表之间的关系你不明白.因此在学SQL语句之前,先介绍一下数据库设计. 下面举例说明数据库设计: 学校需要开发一个系统记录有学生.课程和成绩信息.数据库如何设计? 这里面涉及到两个实体,学生表.课程,这些表为实体表. 这些表之间有什么关系呢?.学生考试出成绩,成绩记录在成绩表. 一个学生可以参加多门课程,关系是1对多. 数据库设计实例 设计数据库和表 安装m

MySQL性能调优与架构设计——第 14 章 可扩展性设计之数据切分

第 14 章 可扩展性设计之数据切分 前言 通过 MySQL Replication 功能所实现的扩展总是会受到数据库大小的限制,一旦数据库过于庞大,尤其是当写入过于频繁,很难由一台主机支撑的时候,我们还是会面临到扩展瓶颈.这时候,我们就必须许找其他技术手段来解决这个瓶颈,那就是我们这一章所要介绍恶的数据切分技术. 14.1 何谓数据切分 可能很多读者朋友在网上或者杂志上面都已经多次见到关于数据切分的相关文章了,只不过在有些文章中称之为数据的 Sharding.其实不管是称之为数据的 Shard

MySQL性能调优与架构设计——第13章 可扩展性设计之 MySQL Replication

第13章 可扩展性设计之 MySQL Replication 前言: MySQL Replication 是 MySQL 非常有特色的一个功能,他能够将一个 MySQL Server 的 Instance 中的数据完整的复制到另外一个 MySQL Server 的 Instance 中.虽然复制过程并不是实时而是异步进行的,但是由于其高效的性能设计,延时非常之少.MySQL 的Replication 功能在实际应用场景中被非常广泛的用于保证系统数据的安全性和系统可扩展设计中.本章将专门针对如何利

【二代示波器教程】第11章 示波器设计—功能模块划分

第11章      示波器设计-功能模块划分 二代示波器的界面上做了五个按钮,分别用于不同功能的配置,本章节就为大家讲解这五个按钮实现的功能. 11.1   主界面上的五个按钮 11.2    Measure测量功能 11.3    ADC电压测量功能 11.4    DAC信号发生器 11.5    Math数字信号处理 11.6    Settings设置 11.7    总结 11.1  主界面上的五个按钮 为了方便各个功能的配置,主界面右侧做了五个按钮,用于实现五个不同功能的配置. 代码

系统架构设计师第七章 软件架构设计

第七章 软件架构设计 考试大纲: 软件架构的概念 软件架构风格 特定领域软件架构 基于架构的软件开发方法 软件架构评估 软件产品线 软件架构设计就是软件系统的"布局谋篇", 软件架构的研究内容主要涉及: 软件架构描述.软件架构设计.软件架构风格.软件架构评价和软件架构的形成方法. 软件设计人员学习软件架构知识旨在站在较高的层面上整体地解决好软件的设计.复用.质量和维护等方面的实际问题. 一.软件架构的概念- (一)软件架构的定义 软件架构为软件系统提供了一个架构.行为和属性的高级抽象,

安卓app设计规范整理和Android APP设计篇(转)

随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近小米的miui 6的发布和魅族手机系统的更新等等. 以小米MIUI6的安卓手机来说,MIUI6进行了全新设计,坚持“内容才是本质”的设计哲学,重新提炼内容,简化图标设计. 所以,我们在进行安卓APP设计时,需要好好调整之前的设计规范和设计细节.根据目前流行的安卓手机的系统体验来完成我们的安卓APP设计规范.应该说这是整理出最全面的安卓app设计规范. 25学堂站在不断更新和完善安卓app设计规范为宗旨!利用周末