类型基础
CLR的Type是可重用抽象体,就是把module再细分的结果。Type的描述存放在CLR的module的元数据中,module里同时存着使type工作的CIL(common intermediate language)或本机代码(machine code).
Type的强命名包括三部分:assembly name, namespace prefix, type name.
以下记录几个容易混淆的东西。
1、access control
public是所有类可见
internal是指在type所属程序集可见
protected是指type自身和子类可见
private是指自身可见
其中,internal和protected是可组合使用的。另外有一个sealed关键字,是用来指示此类(或方法)不可被继承(或覆写即override)。
问题:对于父类private的字段,子类中含有这个字段吗?当然有,只是子类不能访问罢了。继承时,类的内存分配是按照field的大小来分配的,子类中当然也有父类private字段,只是不能访问。
2、可变参数列表 variable parameter list
CLR的System.ParamArrayAttribute属性应用到最后一个参数上,指定可变参数列表,当然,类型只能是参数数组定义的类型了。例如:
public sealed class Dialer {
public static void DialEm(string message,
params string[] numbers) {
for (int i = 0; i < numbers.Length; i++)
Util.Dial(message, numbers[i]);
}
public static void CallFred() {
DialEm("Hi Fred!", "310-555-1716", "781-555-9895");
}
}
3、嵌套类型 Nested Type
java中的嵌套类型是跟随所属类进行实例化的,CLR中的嵌套类型是static成员,是不能被逐一实例化的。例如:
namespace AcmeCorp.LOB {
public sealed class Customer {
public sealed class Helper {
private static int incAmount;
public static void IncIt() {
// legal - methods in nested types can access private
// members of containing type
nextid += incAmount;
}
}
private static int nextid;
public static void DoWork() {
// legal - IncIt is public member
Helper.IncIt();
// illegal - incAmount is private
Helper.incAmount++;
}
}
}
4、字段的static、const、readonly关键字
static是说这个字段是type级别而不是object级别的,所以在内存中这个type的所有实例共享这个字段。这个字段是在type被CLR首次加载的时候分配内存的,初始化也在这个时候。
const和readonly字段都是说这个值不能改变、只能赋值一次,不同之处在于:const是编译时就赋值的,readonly则是在运行时赋值。所以const是字面值,而readonly是根据运行时提供值决定的。
5、类型初始化函数 .cctor
每个类都有自己的构造函数,这个构造函数体在代码中由new来调用;而每个type都有自己的类型构造函数,这个是CLR加载type时候调用的,我们的代码不能调用。
那什么时候CLR调用这个.cctor呢?本来在加载一个type时就该调用了,但是有一个元数据属性beforefieldinit,如果有这个属性的话,调用.cctor就推迟到第一个static field被引用时才调用。这个beforefieldinit是元数据字段,所以是编译器自己加上的。在.net framework中,当你的type没有.cctor只有ctor时,中间语言编译器就自动在IL中加入beforefieldinit标记了。如下图:
class Program
{
internal static long t1;
private static int i = 0;//这里有一个static字段被赋值
//这是.cctor
//static Program()
//{
// t1 = System.DateTime.Now.Ticks;
//}
static void Main(string[] args)
{
Program p = new Program();
}
}
上面这段代码编译后的IL如下
Program类有一个.cctor,而且其IL代码如下,只要没有显式定义.cctor, beforefieldinit属性就会出现。
.class private auto ansi beforefieldinit LinaTest.Program extends [mscorlib]System.Object { } // end of class LinaTest.Program
注意:如果Program类中没有上述代码中的static int i=0 的话,IL中就不会有.cctor了,但是beforefieldinit属性还是有的。说明, 有静态字段初始化表达式才会有隐式.cctor出现(这个是什么原因我还不知道,难道可以没有.cctor吗?)