原书籍《Effective C#:改善C#代码的50个有效方法》 精炼18点

1.优先使用隐式类型的局部变量

为什么:【是为了支持匿名类型】【某些查询操作所获得的结果是IQueryable<T>,而其他一些则返回IEnumerable<T>】

2.常量选择 用 readonly

 

3.:优先考虑is或as运算符,尽量少用强制类型转换

 

 

 

4. 用$ 代替 string.Format()

5.如果需要写回调函数 用委托

6.用null来触发事件

 

7.new修饰符一定要慎重地使用,如果不假思索地滥用,就会给在对象上面调用这种方法的开发者造成困惑。只有当基类所引入的新成员与子类中的现有成员冲突时,才可以考虑运用该修饰符,但即便在这种特殊的情况下,也得仔细想想使用它所带来的后果。除此之外的其他情况决不应该使用new修饰符。

8.变量声明一定要初始化

9.实现单例子模式代码 类中的静态变量初始化

 

 

 10.不在构造函数调用虚函数在(基类的)构造函数里面调用虚函数会令代码严重依赖于派生类的实现细节,而这些细节是无法控制的,因此,这种做法很容易出问题。如果要保证该做法不出错,那么派生类必须通过初始化语句把所有的实例变量都设置好,这使得开发者无法运用很多编程技巧,例如无法根据构造函数的参数来给该对象设定合适的内部状态。换句话说,这要求派生类必须定义默认的构造函数,而且不能带有别的构造函数,这对派生类的开发者来说是很大的负担。你觉得每一位开发者都会按照这套规则来编程吗?我看不太可能。这样写出来的代码以后或许会出现很多错误。由于这种写法难以达到正确的效果,因此,Visual Studio所附带的FxCop及Static Code Analyzer等工具都会将其视为潜在的问题

 11.要以谨慎的态度来施加new、struct及class等约束,因为正如刚才那个例子所示,这样的约束会限定对象的构建方式。如果你要求某对象的默认值必须是0值或null引用,或是必须能够以new()的形式来构建,那么可以给泛型类的类型参数施加这几种约束,但最好不要强行规定。你要考虑泛型参数是否非得满足这些要求才行。很多情况下,你都是想当然地认为它必须符合某一条要求(例如必须能够以new T()的形式来构建),其实即便不满足该要求,也依然可以用别的办法来编写代码(例如可以改用default(T)实现),因此,这可能只是一种思维定势而已。你得仔细想想是否真的需要这样做。设定约束是为了向客户端编程者提出某种要求,但如果要求提得太多,那么愿意使用这个类的人就会变少,这反而违背了创建泛型类的初衷——创建这样的类本来是想叫它在各种场合之下都能够有效得以运用。约束条件可以确保用户所指定的类型是安全的,但要想满足这些条件,用户可能得多做一些工作才行,因此,设定约束条件时,需要在二者之间权衡,将多余的条件去掉,只把那些确实有必要的条件保留下来

12通过IComparable<T>及IComparer<T>定义顺序关系 如果想把某个类型的对象放入集合以执行排序与搜索,那么需要将这些对象之间的关系定义出来。.NET Framework引入了两种用来定义该关系的接口,即IComparable<T>及IComparer<T>。

13.只把必备的契约定义在接口中,把其他功能留给扩展方法去实现

14.可以考虑用查询而不是直接foreach 有一个话题总能够引发讨论,那就是通过查询机制实现出来的代码是不是要比用循环写出来的慢一些。你确实可以举出一些例子,用来说明手写的循环代码要比查询式的代码更快,但这种特例并不代表一般的规律。如果你怀疑查询式的写法在某种特定情况下运行得不够快,那么应该首先测量程序的性能,然后再做论断。即便确实如此,也不要急着把整个算法都重写一遍,而是可以考虑利用并行化的(parallel)LINQ机制,因为使用查询语句的另一个好处在于可以通过.AsParallel()方法来并行地执行这些查询。

15. foreach循环查询List 优化写法

【用yield return语句来编写迭代器方法,以便依次处理序列中的各个元素。如果经常编写这些方法,那么就会发现方法的代码通常由两部分组成,一部分用来迭代该序列,另一部分用来在序列中的元素上执行操作。比方说,你有可能只想处理符合某项标准的元素,也有可能想在每N个元素中抽取一个元素,或是跳过一批元素。】

 

 

 

 

16.Linq是一种延迟查询,是把所有语句全部找到之后再一次性求值的,而不是写一个.where 就会去数据库查询到数据

程序必须运行到number变量等于int.MaxValue时才会停下,因为查询语句需要逐个判断序列中的每一个元素,并根据其是否小于10来决定要不要生成该元素。这样的逻辑导致它必须把整个序列全都处理一遍才行。

 

 

 

 

 

 

 17.不要在Func与Action中抛出异常

 

如果既要编写可以在发生异常时安全运行的查询操作,又要使这些操作之间能够相互拼接,那么就得注意代码的写法了。一旦查询时所执行的Action与Func抛出异常,程序中的数据就很难保持一致。由于你无法确定已经处理与尚未处理的元素各有多少,因此没办法通过适当的措施将程序的状态复原。不过,你可以考虑令这些查询操作返回新的元素,而不是直接在源序列上面修改,以确保该操作在无法完整执行的情况下不会破坏程序的状态。

18.IEnumerable<T>所设计的那些扩展方法都会将其视为委托。反之,针对IQueryable<T>的那些扩展方法用的则是表达式树(expression tree)

 

posted @ 2022-08-17 11:10  12不懂3  阅读(107)  评论(0编辑  收藏  举报
创作不易,请勿抄袭,欢迎转载!