看了这个:http://blog.jobbole.com/71124/
然后发现自己连这些错误怎么犯都不知道。sigh。。。
一个一个来学习吧。
【1】关于c#的值类型和引用类型
自己在程序里完全没有注意过这个东西啊。区分值类型和引用类型神马的。
C#中,变量是值还是引用仅取决于其数据类型。
C#的值类型包括:结构体(数值类型,bool型,用户定义的结构体),枚举,可空类型。
C#的引用类型包括:数组,用户定义的类、接口、委托,object,字符串。
在内存里,值类型是定义在线程的堆栈上,而引用类型是定义在托管堆上,由GC负责回收。(http://www.cnblogs.com/siqing99/archive/2012/04/03/2430918.html)
(但数组的元素,不管是引用类型还是值类型,都存储在托管堆上。)
因此在做传递时,值类型A(x,y)和B(x,y),A.x的修改并不能造成B.x的任何变动;
然而,引用类型C(x,y)和D(x,y),C.x的修改会直接影响到D.x的值。
======Q:static修饰的引用类型呢?
======A:仍然同理,只不过static之后,这个引用类型(其实这里就是类)在程序运行初始就执行了。因此不用再实例化。
需要注意的问题:
1.应该尽可能地将值类型实现为具有常量性和原子性的类型。
区别就是:
class A ,没有构造函数,属性123
实例化的时候,A.1=xxx;//这时候A.2和A.3都是非法的
常量性和原子性修改之后,就是这样:
class A ,构造函数A(属性123)
实例化的时候,A=new A (123)
这样就是一次原子操作,不会发生非法的事情。
2.应该尽可能地确保0为值类型的有效状态。
有时候创建了一个类型之后,会发生0和empty非法的情况。比如
sex{male,female}
应该改成
sex{none,male,female}
3.应该尽可能地减少装箱和拆箱。
装箱和拆箱是值类型和不明类型的引用类型之间的互相赋值。
比如 int A=1;
object B=A;//装箱
object A=new object();
int B=(int)A;//拆箱
这种装箱和拆箱的操作对性能的损耗是很大的,而且有时还会发生诡异的错误。解决方法是:
不使用隐性的强制转换
在转换时,多使用Convert.ToInt32,或者xxx.ToString()
#另一个例子是ArrayList
在ArrayList的Add操作里,有一个隐性的强制转换。而泛型List<T>的Add()函数就没有这个强制转换的bug。
在发生错误时,可以考虑是否是因为隐性转换的原因,并将ArrayList换成List<T>来处理。