.ctor(下)
在继承中对象构造过程
编译后用ILDasm打开生成的exe文件:
可以看到三者都有一个.ctor,B、C中有.cctor,而A没有,打开B,C的.cctor,可以看到它们都负责初始化自己的静态字段,现在主要来看它们的.ctor。
先看类C的.ctor:
在C被实例化时,它最先初始化在声明时同时赋值的字段(非静态),此处是将3赋给z,然后它会调用其基类的.ctor(),然后再调用自己的实例方法m3(),值得注意的是,在执行显式定义的构造方法体中的代码前,会先调用其基类的构造方法(创建基类的实例)。
再来看类B的.ctor():
那A的.ctor()就不再看了,可以猜到它一定是在做这样的事:
1、 将1赋给实例的x字段;
2、 调用基类System.Object的构造方法.ctor来创建基类的实例;
3、 调用实例方法m1();
总结
看下面这段程序:
1 public class A 2 { 3 public int x = 1; 4 public A() { m1(); } 5 public void m1() { } 6 } 7 8 public class B : A 9 { 10 public int y = 2; 11 public static string sb = "B"; 12 public B() { m2(); } 13 public void m2() { } 14 } 15 16 public class C : B 17 { 18 public int z = 3; 19 public static string sc = "C"; 20 public C() { m3(); } 21 public void m3() { } 22 }
编译后用ILDasm打开生成的exe文件:
可以看到三者都有一个.ctor,B、C中有.cctor,而A没有,打开B,C的.cctor,可以看到它们都负责初始化自己的静态字段,现在主要来看它们的.ctor。
先看类C的.ctor:
1 IL_0001: ldc.i4.3 2 3 IL_0002: stfld int32 ConsoleApplication1.C::z 4 5 IL_0007: ldarg.0 6 7 IL_0008: call instance void ConsoleApplication1.B::.ctor() 8 9 IL_000d: nop 10 11 IL_000e: nop 12 13 IL_000f: ldarg.0 14 15 IL_0010: call instance void ConsoleApplication1.C::m3()
可以看到:
在C被实例化时,它最先初始化在声明时同时赋值的字段(非静态),此处是将3赋给z,然后它会调用其基类的.ctor(),然后再调用自己的实例方法m3(),值得注意的是,在执行显式定义的构造方法体中的代码前,会先调用其基类的构造方法(创建基类的实例)。
再来看类B的.ctor():
1 IL_0001: ldc.i4.2 2 3 IL_0002: stfld int32 ConsoleApplication1.B::y 4 5 IL_0007: ldarg.0 6 7 IL_0008: call instance void ConsoleApplication1.A::.ctor() 8 9 IL_000d: nop 10 11 IL_000e: nop 12 13 IL_000f: ldarg.0 14 15 IL_0010: call instance void ConsoleApplication1.B::m2()
同样,我们可以看到,在实例化B时,它会先把2赋给自己的y,然后再调用基类A的构造方法,最后再调用自己的实例方法m2()。
那A的.ctor()就不再看了,可以猜到它一定是在做这样的事:
1、 将1赋给实例的x字段;
2、 调用基类System.Object的构造方法.ctor来创建基类的实例;
3、 调用实例方法m1();
总结
1、.ctor是构造方法;
2、.cctor是类型初始化器,在C#中也就是静态构造函数;
3、当类C实例化时,会先对声明时就进行赋值的字段赋值,然后调用基类的构造函数,基类再以同样的方法构造自己,一直到顶层的System.Object,然后再回来执行C的显式构造方法中的代码,就是这么一个递归的过程。