標題比較抽象,所以我寫了一個Demo來說明問題:
public class A
{
public A()
{
Console.WriteLine("A的構造函數被調用");
}
}
public class B : A
{
private X x = new X(); //初始化器
}
public class X
{
public X()
{
Console.WriteLine("X的構造函數調用");
}
}
static void Main(string[] args)
{
B b = new B();
}
在調用子類的構造函數之前,會先調用基類的構造函數,那初始化器和基類的構造函數到底誰先執行呢?
因為初始化代碼會在構造函數中的代碼之前執行,所以我過去錯誤的認為:
public class B : A
{
private X x = new X(); //初始化器
}
等價於:
public class B : A
{
private X x;
public B()
{
x=new X();
}
}
所以我也錯誤的認為基類的構造函數是在子類的初始化器之前執行的,上面的Demo執行的結果剛好相反,是:
X的構造函數調用
A的構造函數被調用
這表明子類的構造器先執行了,讓我們看看生成的構造函數的IL代碼:
public class B:A
{
private X x;
public B()
{
x = new X();
}
}
生成的構造函數的IL代碼是這樣的:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代碼大小 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void ConsoleApplication1.Program/A::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: newobj instance void ConsoleApplication1.Program/X::.ctor()
IL_000e: stfld class ConsoleApplication1.Program/X ConsoleApplication1.Program/B::x
IL_0013: nop
IL_0014: ret
} // end of method B::.ctor
從代碼可以看出是先調用基類的構造函數的!
public class B : A
{
private X x = new X();
}
生成的構造函數的IL代碼是這樣的:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代碼大小 19 (0x13)
.maxstack 8
IL_0000: ldarg.0
IL_0001: newobj instance void ConsoleApplication1.Program/X::.ctor()
IL_0006: stfld class ConsoleApplication1.Program/X ConsoleApplication1.Program/B::x
IL_000b: ldarg.0
IL_000c: call instance void ConsoleApplication1.Program/A::.ctor()
IL_0011: nop
IL_0012: ret
} // end of method B::.ctor
可以看出是先調用初始化器的代碼,然後再調用基類構造函數的!可見使用初始化器和不使用初始化器還是有區別的,主要區別是基類構造函數的調用順序不同!
C#編譯器為什麼這樣設計,我也沒有想到太合理的原因,大家有什麼看法呢?
請大家多多指教啊!