菜园子  

一个普遍的问题是:当我现在的一些做法完全可以胜任我的需求的时候, 为什么我要改变, 答案是你可以做的更好, 改变工具或者语言的目的就是让工作更有效率, 改变习惯的目的也同样如此.

l 习惯1:始终使用属性而不是通过数据成员来处理数据, 原因主要有:

1. Net对属性的支持远远大于对成员的支持,属性被当做方法封装, 虽然他在读取上跟数据成员很类似, 但是他在行为上却是个方法, 故而在.net的绑定类里面是只支持属性而不是公用的数据成员。

2. 对属性进行多线程的操作要容易得多, 因为属性被实现成方法, 所以像lock一样进行线程同步要方便得多.

3. 属性对于面向的支持比数据成员好很多, 例如属性可以是抽象的, 数据成员不行.接口里定义的是属性而不是数据成员.

4. 索引器是通过属性来完成的.

5. 最后一点, 属性和公共数据成员虽然在代码上一样,但是不能认为代码一样就可以改了直接用, 一定要编译后才可以,因为属性和数据成员内部实现是不同的.

l 习惯2: 选择is或者as操作符而不是做强制类型转换:

1. C#是一种强类型语言, 好的习惯是避免将一种类型强制转换成另一种类型,可以尝试先用is进行转换再通过as进行转换, 这样做的好处是更安全,效率更高, 用as和is运算符进行转换时,并不是对所有的用户定义的类型都能完成的。它们只在类型和目标类型匹配的时候,转换才能成功。强制转换要通过异常来监控,因为其失败是会抛异常出来, 而as是安全的返回null.

2. 强制转换与as转换最大的区别表现在如何对待用户定义类型的转换,is和as首先会检测目标对象是否是要转换的类型或其派生类型, 如果不是,转换会失败.而强制转换则是通过将一个对象转换成需要的类型, 包括对内置数据类型的转换,强制将long转换到short会可能丢失数据. 另外,编译器在对用户自定义类型进行类型转换的过程是在编译时进行的, 它不了解运行时该对象会是什么类型.

3. Foreach是采用强制转换的, 因此可能会产生BadCastException异常.

l 习惯3:选择变量初始化而不是赋值语句

1. 定义类的时候往往会有多个构造函数, 避免多次构造造成不同步的方法之一就是在定义对象时使用初始化器对变量直接初始化, 这样不管添加多少个构造函数都不会有不同步的问题.

2. 使用初始化器可以避免在类中出现未定义的变量,但它也不万能的, 有三种情况是要注意的:

A:将对象初始化为0或null, 因为系统会在你的任何代码执行前为所有的内存内容都初始化0, 系统置0是基于底层的CPU指令, 对整个内存块进行设置.你的任何其他置0都是多余的,因为c#编译器会未你的代码添加额外的命令来重新将内存置0。

B:不要对同一个对象同时采用构造器和构造函数进行初始化,因为在构造函数执行时先前通过构造器创建的对象会变成垃圾对象.

C:初始化器不利于异常的捕捉, 应该把初始化器放到构造函数里面去,这样在构造时的异常就可以被捕捉到.

l 习惯4:避免返回内部对象的引用

1. 我们常常定义一些只读属性, 目的就是为了不让调用者修改这个属性, 但是有些时候,例如定义了一个返回Dataset的只读属性, 调用者还是可以通过读属性来操作这个Dataset, 这就违反了当初设计的初衷.

2. 以Dataset为例,当你希望用户能查看你的数据但不能做出任何修改的时候,可以通过强制在Datatable上创建一个dataview, 设置dataview的一些Allownew,AllowEdit等属性为false来限制修改, 同时,只读属性返回Ilsit对象即可.

l 习惯5:选择小而简单的函数

1. .net运行时调用JIT编译器,用来把C#编译器生成的IL指令编译成机器代码,这一任务在应用程序的运行期间是分步进行的.JIT并不是在程序的一开始就编译整个程序,CLR是一个函数接一个函数的调用JIT编译器, 这可以让启动开销最小化到合理的级别. 例如在if-else语句中, 在if和else部分都定义过多的语句是不合理的, 因为JIT编译器在第一次调用的时候两个分支条件都会编译,而事实上只有一条是有效的,这时候把代码块分解成若干小函数会更有效得多.

2. 另外一个原因是简单小巧的函数在编译的时候可以被进行”可登记处理”(Enregistration), 可登记处理就是指进程选择哪些局部变量可以被存储到寄存器中,这显然比存到堆栈中要好.

posted on 2010-06-08 15:28  菜园子  阅读(146)  评论(0)    收藏  举报