基础(二)
小结:
1. 静态类【static class】
a. 不能被实例化,值类型(如:结构)不能用static修饰,因为CLR总是允许值类型可以被实例化。
b. 静态类直接继承自System.Object
c. 静态类不能实现任何接口,因为接口中的方法是要通过接口的实现类实例化后访问的,而静态类是不能实例化的
2. Constants【常量】
a. 在编译期间赋值,隐式认为是static的,但是在声明时不能用static修饰
b. 当我们的代码中引用了一个const常量时,compiler会先在程序集的metadata中查找该常量的声明,然后提取它的值并将其值直接放进IL Code中,也就是说在Runtime时,不需要分配内存空间来存放常量的值,所以我们获取不到常量的地址
3. Fields【域】
域就是一个数据成员,该成员可以持有一个值类型的实例,也可以持有一个对引用类型的引用
关于域的readonly修饰符:
a. 在声明readonly变量时,可以对其赋值也可以不赋值
b. 只能在构造函数里修改其值,其他地方都不允许
c. 如果一个引用类型变量被readonly修饰,那么这个变量将是不可变的,即不能用它再去引用一个新的对象,如:
public sealed class Test{
public static readonly char[] tt = new char[]{'A','B','C'};
}
如果:Test.tt = new char[]{'X','Y','Z'};//将tt又引用了一个新的对象,这是不允许的
4. 字符串
a. 字符串是不可变的,即字符串在创建之后就再也不能改变,其中包括变长、变短或者修改其中的任何字符。
如:
if (str.ToUpperInvariant().Substring(10,21).EndsWith("EXE"))
{
...
}
----以上会产生两个临时的字符串,ToUpperInvariant()会产生一个,Substring(10,21)会产生一个,原str中的内容是不变的
----基于此,要想高效的操作大量字符串,就使用StringBuilder类
b. 字符串留用
内存中可能存在同一个字符串的多个实例,这会造成内存的浪费,因为字符串是“不可变”的。如果只在内存中保留字符串的一个实例,那么将显著提高内存的利用率,需要引用字符串的所有变量只需指向同一个字符串对象。
如果应用程序经常对字符串进行区分大小写的、序号式的比较,或者事先知道许多字符串对象都具有相同的值,就可以利用CLR中的字符串留用机制来显著提高性能。CLR初始化时,它会创建一个内部哈希表,在这个表中,key是字符串,而value是对托管堆中的String对象的引用。哈希表最开始是空的,String类提供了两个方法以便访问这个内部哈希表:
public static string Intern(string str);
----获取一个String,获得它的哈希码,并在内部哈希表中检查是否有相匹配的。如果已经存在一个完全相同的字符串,就返回对现有的String对象的一个引用,并不会再次新建一
个String对象。如果不存在,就会创建字符串的副本,并将副本添加到内部哈希表中,并返回对这个副本的一个引用。
public static string IsInterned(string str);
----获取一个String,并在内部哈希表中查找它。如果哈希表中有一个匹配的字符串,就返回对留用字符串对象的一个引用,如果没有,则返回null,不会将字符串添加到哈希表中
5. Parse方法与TryParse方法
取Int32为例,在Int32类中的定义为:
public static int Parse(string s); //转换不成功会抛出异常
public static bool TryParse(string s, out int result); //转换成功返回true,不成功则返回false,不会抛出异常
6. 关于异常抛出的起始点
----CLR只会记住最近抛出异常的位置
a.
try{...} catch(Exception e) { ... throw e; //将捕获到的异常再次抛出,CLR会重设异常的起始点,即把异常的起始点改成现在这里 }
b.
try{...} catch(Exception e) { ... throw; //将捕获到的异常再次抛出,CLR不会重设异常的起始点 }
7. 在使用lock, using, foreach语句时,C#编译器会自动把其代码放在try语句块中,然后在finally语句块中做些资源关闭操作,如:调用Dispose()方法