《编写高质量代码 改善C#程序的157个建议》 - 书摘精要

(P6) String.Format方法在内部使用StringBuilder进行字符串的格式化;

(P8)

System.Convert还支持将任何自定义类型转换为任何基元类型,只要自定义类型继承了IConvertible接口就可以;

System.BitConverter提供了基元类型与字节数组之间相互转换的方法;

(P11)

如果类型之间都上溯到了某个共同的基类,那么根据此基类进行的转型(即基类转型为子类本身)应该使用as;子类与子类之间的转型,则应该提供转换操作符,以便进行强制转型;

转型操作符实际上就是一个方法,类型的转换需要手工写代码完成;

(P12) as操作符有一个问题,即它不能操作基元类型。如果涉及基元类型的算法,就需要通过is转型前的类型来进行判断,以避免转型失败;

(P13) 引发异常这个过程会对性能造成损耗;

(P15) 语法T?是Nullable<T>的简写,两者可以相互转换;

(P16)

??最大的用处就是将可空类型的值赋值给对应的基元类型进行简化;

const和readonly的本质区别如下:
const是一个编译期常量,readonly是一个运行时常量;
const只能修饰基元类型、枚举类型或字符串类型,readonly没有限制;

(P20) 创建枚举的理由之一,就是为了代替使用实际的数值;

(P22) CLR支持在类型中,通过使用operator关键字定义静态成员函数来重载运算符;

(P25) 泛型出来后,就建议尽量不使用所有非泛型集合类;

(P28) 在FCL中,string的比较被重载为针对“类型的值”的比较,而不是针对“引用本身”的比较;

(P29)

对于引用类型,要定义“值相等性”,应该仅仅去重载Equals方法,同时让“==”表示“引用相等性”;

由于操作符“==”和“Equals”方法从语法实现上来说,都可以被重载为表示“值相等性”和“引用相等性”。所以,为了明确有一种方法肯定比较的是“引用相等性”,FCL中提供了Object.ReferenceEquals方法。该方法比较的是:两个示例是否是同一个示例。

(P31) GetHashCode方法应该基于那些只读的属性或特性生成HashCode;

(P32) Object的ToString方法会返回当前类型的类型名称;

(P38) 在浅拷贝过程中,应该将字符串看成是值类型;

(P42) 始终使用dynamic来简化反射实现;

(P44) 在元素数量可变的情况下不应使用数组;

(P49) foreach用于遍历一个继承了IEmuerable或IEmuerable<T>接口的集合元素;

(P55)

泛型使用一对<>括号将实际的类型括起来;

非泛型集合在System.Collections命名空间下,对应的泛型集合则在System.Collections.Generic命名空间下;

(P73) 任何LINQ查询都能通过调用扩展方法的方式来替代;

(P74) Lambda表达式是一个简单的委托,运算符“=>”左边代表的是方法的参数,右边的是方法体;

(P97) 委托也是一种类型,跟任何FCL中的引用类型没有差别;

(P98) Lambda表达式操作符“=>”的左侧是方法的参数,右侧是方法体,其本质是匿名方法;

(P103) 委托是方法指针;委托是一个类,当对其进行实例化的时候,要将引用方法作为它的构造方法的参数;

(P118) 如果类型需要显式释放资源,那么一定要继承IDispose接口;

(P135) 要让事件不能被序列化,需使用改进的特性语法[field:NonSerialized];

(P160) 直接 throw exception 而不是 throw 将会重置堆栈信息;

(P179) 异步模式借助于线程池,极大地节约了CPU的资源;

(P180) 锁定使用关键字lock和类型Monitor,两者没有实质区别,前者其实是后者的语法糖;

(P181) EventWaitHandle和Semaphore提供的都是单应用程序域内的线程同步功能,Mutex提供了跨应用程序域阻塞和解除阻塞线程的能力;

(P187) 类型的静态方法应当保证线程安全,非静态方法不需实现线程安全;

(P189) 用Thread创建的线程默认是前台线程,也就是IsBackground属性默认是false;

(P223) 锁其实就是让多线程变成单线程(因为同时只允许有一个线程访问的资源);

(P226)

抽象类可以有构造方法,即使没有为抽象类指定构造方法,编译器也会为我们生成一个默认的protected构造方法;

抽象类的构造方法不应该是public或internal的;

抽象类设计的本意只能让子类继承,而不是用于生成实例对象;

抽象类只需对子类可见就行;

(P228)

类型的属性应该在构造方法调用完毕之前完成初始化工作;

如果字段没有在初始化器中设置初始值,那么它就应该在构造方法中初始化;

(P229)

初始化器属于编译器的语法糖,它在经编译后,在构造方法的最开始处执行;

可以将初始化器理解为构造方法的一部分;

(P229)

如果子类中的方法前面带有new关键字,则该方法被定义为独立于基类的方法;

如果子类中的方法前面带有override关键字,则子类的对象将调用该方法,而不是调用基类方法;

(P231)

子类override父类的方法,即使子类转型为父类,调用的还是子类的方法;

子类new了父类的方法,故子类方法和基类方法完全没有关系了,只要子类被转型为父类,则针对子类调用的都是父类方法;

(P239) 静态方法在加载时机和内存使用上与实例方法完全一致;

(P241)

扩展方法必须在静态类中,且该类不能是一个嵌套类;
扩展方法必须是静态的;
扩展方法的第一个参数必须是要扩展的类型,而且必须加上了this关键字;
不支持扩展属性、事件;

(P245) 抽象类解决的是“Is a”,接口解决的是“Can do”;

(P253) 单例应该同时是一个sealed类型;

(P255) 对静态引用类型的初始化应该使用静态构造方法。但是,如果一个静态类只有值类型的变量,则可以放宽这种限制;

(P257) 如果必须出现一个嵌套类,应该将其实现为private;

(P301) 只要是泛型,就应该以T作为前缀命名;

(P311)

类型成员的修饰符默认是private;

类或接口的默认修饰符为internal;

(P339) 架构模式是为了让单元测试变得更方便;

你可能感兴趣的:(高质量代码)