【进阶修炼】——改善C#程序质量(6)

90,不应为抽象类指定public的构造函数。

抽象类即使指定了public的构造函数,也是不能实例化的,编译通不过。抽象类的构造函数应该设定为protected,它的作用应该是初始化自己的成员,以及可以被子类构造函数调用。设定为public权限毫无意义。

91,可见字段应该重构为属性。

属性比字段有更好的灵活性,可以加入代码控制,可以在类型内部实现线程安全访问,可以让类型得到通知(如WPF系统),这些都是字段所不具备的。当然,如果仅限于类型内部使用,应该用字段。

92,谨慎将数组或集合作为属性。

即使这个属性是只读的(没有set方法),那也只是针对集合的引用而已,集合内部的元素是可以被改变的。我们可以将集合作为私有变量保存,然后提供必要的方法来访问这个集合。如果非要公开这个集合,也要设定为只读属性。

93,构造方法应初始化主要属性和字段。

初始化器实际上就是在构造函数代码块的前面插入一些代码来执行初始化操作,我们应该为必要的字段和属性提供一个初始值,而不要使用时得到一个null值。

94,区分override和new关键字。

Override是实现多态的关键,子类的方法前面有override关键字,则子类的对象将调用该方法。如果子类的方法前有new关键字,则该方法是独立于基类的新方法,父类型的引用不会调用该方法,而只能调用父类的方法。

95,不要在构造函数中调用虚成员。

虚成员被子类重写后可能用到子类的成员变量,而父类的构造函数是优先于子类构造函数执行的,这时,子类的成员变量还没有得到初始化,会引发Null异常。

96,成员应优先考虑公开基类型或接口。

比如方法或属性返回接口,我们以后改变了内部的实现细节,外部代码根本不用修改,可以获得更好的灵活性。另外,可以进一步控制成员的可见性,将可见性限制得更低。

97,优先考虑基类型或接口作为参数传递。

上面一条是考虑成员的可见性,这一条建议是考虑函数的适用范围,抽象越高,通用性越好。

98,用params减少重复的参数。

如果参数个数不定,参数类型又一致,可以考虑params减少参数数量。

99, 重写时不要使用子类参数。

也就是不要改变重写方法的参数类型。事实上改变了参数的类型,被认为是两个不同的方法了。

100, 静态方法和实例方法没有区别。

这一点初看有点纳闷,它是指静态方法和实例方法都是被分配到类型的方法表上的。静态方法在多线程环境中也需要考虑方法内部的线程同步,和实例方法是一样的。静态方法也需要类型对象被分配才能执行,而这一步是我们第一次用到类型的时候CLR为我们自动创建的,我们感觉不到而已。

101, 使用扩展方法,为类型“添加”方法。

扩展方法本质是静态函数,它只能被放在静态类中,使用它可以减少我们的继承体系结构,我们可以对密封类,第三方提供的类,甚至接口使用扩展方法,使得这些方法看起来好像就是它们自己的一样,而不需修改类的内部结构。扩展方法实际上是静态函数的一种语法糖,但是有了扩展方法,我们使用类会变得更加自然,更加面向对象。

102,区分抽象类和接口的适用场合。

接口支持多继承,抽象类则不能。接口只包含声明,不能实现,抽象类则可以。接口增加成员后,所有的继承者都必须重构,抽象类则不用。所以,接口一旦设计好就应该是保存不变的,功能尽可能单一,以利于重用。如果对象间多个功能相近且关系紧密,应该使用抽象类。如果对象间关系不紧密,但若干功能有共同的声明,则使用接口。抽象类解决的是“Is a”关系,接口解决的是“Can do”关系。

103,区分组合和继承的应用场合。

继承带来的多态性是它相较于组合的优势,但是在大多数的应用场合,我们都不需要多态。继承代表的是“Is a”,组合代表的是“Has a”,这是两种不同的设计理念。继承能提高代码的可重用性,比如上面建议中的为函数的返回值和参数指定基类型,可以提高函数的适用范围。但是继承也有缺点,继承了太多的方法和属性,这些方法和属性都会被曝露出来,给使用者带来麻烦,同时也破坏了封装性。组合具有更好的封装性,我们只提供必要的方法和属性。

104,用多态代替条件语句。

多个case语句的函数,如果添加分支,这个函数就会被修改,如果考虑多态,我们只需添加一个新的类。这就实现了面向对象的“开闭原则”,对修改关闭,对扩展开放。当然这一步,往往不是设计初期就考虑的到的,经常在重构代码的过程中来实现的。

105,使用私有构造函数强化单例。

在实现Singleton模式时,应只提供一个private的构造函数。

106,为静态类添加静态构造函数。

静态构造函数只执行一次,不能带参数,代码无法调用它。静态构造函数可以对异常进行捕获,如若用静态初始化器则不能捕获异常。

107,区分静态类和单例。

单例是一个类的实例,而静态类不是。静态类没有继承和多态的特性。

108,将类型标识为sealed。

如果确信类不会被继承了,就应该将其标为sealed,避免被其他类型继承,控制继承的深度。另外,标记为sealed的类型,成员的protected关键字已经没有意义了。

109,谨慎使用嵌套类。

当某个类型需要访问另一个类型的私有成员是可以将其设计为嵌套类,嵌套类可以访问外部类的私有成员。并且要始终注意,确保嵌套类为private的,即它的可见性只能限定于外部类型内部。

110,用类来代替Enum。

这看起来有点奇怪。它的出发点是类比枚举拥有更多的可扩展能力,可以添加更多的附加信息。如果没有这些附加信息,则应该使用枚举,枚举是值类型,效率更高。具体的实现方法是,让类的构造函数为private,并提供public static readonly 的各个枚举类。

111, 避免双向耦合。

即两个类型间的互相引用。如果两个类型在不同的项目中,则会造成循环参照。解除双向耦合的方式就是提取一个公共的接口,让他们都去依赖这一个接口。

112, 将现实世界中的对象抽象为类,将可复用的对象圈起来就是命名空间。

这一点要求我们对类要有一定的组织,否则代码会越来越混乱。

时间: 2024-07-28 18:21:01

【进阶修炼】——改善C#程序质量(6)的相关文章

【进阶修炼】——改善C#程序质量(1)

这是一个大纲形式的概要,以便自己可以花较少的时间反复阅读.在开发中,多加注意这些有用的建议,让自己成为一个更优秀的程序员.内容主要来自<编写高质量代码-改善C#程序的157个建议>(陆敏技),这本书写的真的很好,都是些实战经验的总结,建议大家购买,这其中的建议不仅仅适合于C#,只要你做.NET开发,阅读此书都会从中受益.同时,其他书籍和资料的一些好的编程建议,我也会不断更新到这里. 1, 字符串使用. 应避免发生装箱:避免分配额外的内存:考虑使用StringBuilder来替代string.s

【进阶修炼】&mdash;&mdash;改善C#程序质量(9)

140,使用默认的访问修饰符. 如果不加访问修饰符,成员变量的默认是private的,类默认是internal的.为了明确访问的权限,我倒是建议都加上访问修饰符,这省不了多少代码. 141,不知道该不该加大括号的时候就加上. 大括号会多占用两行代码,到底一行语句的代码需不需要加大括号这是一个争论.但是为了避免引入不必要的bug还是加上吧. 142,总是提供有意义的命名. 我们不希望看到如iTemp的命名,类似于i的命名只应该出现在循环中.变量的命名应尽可能表达它应该表达的意思,不要太随意的命名,

【进阶修炼】&mdash;&mdash;改善C#程序质量(2)

16, 元素可变的情况下应避免用数组. 数组是定长的集合,可以考虑用ArrayList或List<T>集合.ArrayList元素是object类型,有装箱的开销,性能较低.另外Array类提供了Array.CreateInstance来创建数组,Array.Copy来拷贝数组,但这牵涉到新数组的创建,会增加开销. 17, 多数情况下用foreach代替for循环. 18, Foreach不能代替for. Foreach不能对元素进行增删操作,不能访问序号. 19, 使用对象初始化器和集合初始

【进阶修炼】&mdash;&mdash;改善C#程序质量(7)

113,声明变量时考虑最大值. Ushort的最大值是65535,用于不同的用途这个变量可能发生溢出,所以设计时应充分了解每个变量的最大值. 114,MD5不再安全. MD5多用于信息完整性的校验.R=H(S),MD5的算法是不可逆的,也就是我们几乎没有可能根据生产的MD5码去还原原文.但是我们可以使用穷举的办法生成MD5码来对比,由于我们平常设定的密码都比较简单,如:123456,根本不用很长的时间就会被破解掉.为了有效防止破解,一个可行的做法是为我们的密码固定加一个字符串"%¥#--@!&a

【进阶修炼】&mdash;&mdash;改善C#程序质量(3)

32, 总是优先考虑泛型. 泛型代码有很好的重复利用性,和类型安全性. 33, 应尽量避免在泛型类中声明静态成员. 静态成员达不到共享的目的.List<int>和List<String>是两个不同的类型,而静态成员是针对类型的.当然2个List<int>之间是可以共享静态成员的,但为了不必要的混淆,应该避免使用静态成员. 34, 为泛型参数添加约束. 没有约束的参数,功能是有限的,添加了约束后,我们就可以使用约束类型的方法和属性了,程序更加灵活. 35, 使用Defau

【进阶修炼】&mdash;&mdash;改善C#程序质量(5)

71, 区分异步和多线程的应用场景. 计算机的很多硬件,如硬盘,光驱,声卡,网卡都有DMA(Direct Memory Access)功能,它可以不占用cpu的资源,而异步的提出恰恰就是基于这个的.而多线程是操作系统上的并行执行的代码,是会占用cpu资源的.所以关于这两种的使用场景建议是:1)对于I/0密集型操作使用异步.2)对于计算密集型操作使用多线程. 72, 在线程同步中使用信号量. 值类型是不能被锁定的,引用类型上的等待机制,分为锁定和信号同步.锁定通过lock关键字或Monitor来完

【进阶修炼】&mdash;&mdash;改善C#程序质量(4)

46, 显示释放资源,需要实现IDisposable接口. 最好按照微软建议的Dispose模式实现.实现了IDisposable接口后,在Using代码块中,垃圾会得到自动清理. 47, 即使提供了显示的释放方法,也应该在终结器中提供隐式实现. 因为我们不能保证用户会主动去调用这个释放方法,但我们要保证在垃圾回收时,这些资源能得到清理. 48, Dispose方法应该允许被多次调用. 我们可以创建一个变量disposed来标明对象是否被释放了. 49, 在Dispose模式中应提供一个受保护的

【进阶修炼】&mdash;&mdash;改善C#程序性能(1)

这是一个大纲形式的提点,以便自己可以花较少的时间时常浏览.在开发中,多加注意这些有用的建议,让自己成为一个更优秀的程序员.内容主要来自<编写高质量代码-改善C#程序的157个建议>(陆敏技),这本书写的真的很好,都是些实战经验的总结,建议大家购买此书,这其中的建议不光适合于C#,只要你做.NET开发,阅读此书都会从中受益.同时,如其他书籍和资料有好的建议,我也会不断更新到这里. 1, 字符串使用. 应避免发生装箱:避免分配额外的内存:考虑使用StringBuilder来替代string.str

Android 控件进阶修炼-仿360手机卫士波浪球进度控件

技术:Android+java 概述 像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitmap的方式,大概的方法原理是: (1)首先用clipPath裁剪园区域, (2)然后用4张图来不断绘制到画布上,再用偏移量来控制移动的速度,从而形成波浪动态效果. (3)有一点需要注意的是,裁剪圆的时候用到的clipPath这个方法,在android 4.1,和4.2等某些系统上,裁剪出来不是圆,而是矩形