测试一:
class Base
{
static Base()
{
Console.WriteLine("Static Base");
}
public Base()
{
Console.WriteLine("Base");
}
}
static void Main(string[] args)
{
Base b = new Base();
Console.Read();
}
打印结果:Static Base
Base
测试二:
class Child : Base
{
static Child()
{
Console.WriteLine("Static Child");
}
public Child()
{
Console.WriteLine("Child");
}
}
在测试一的基础上增加子类,实例化子类打印结果:
Static Child
Static Base
Base
Child
测试三:
abstract class A
{
public A()
{
PrintFields();
}
public virtual void PrintFields() { }
}
class B : A
{
int x = 1;
int y;
public B()
{
y = -1;
}
public override void PrintFields()
{
Console.WriteLine("x={0},y={1}", x, y);
}
}
实例化子类,打印结果:x=1,y=0
子类x赋值1,然后子类构造函数先调用父类的构造函数,因为是重写了,所以父类构造函数调用的方法是子类的方法,这个时候x=1,y没有赋值,所以是0
测试四:
class A
{
static int x = 1;
static int y = 1;
public A()
{
PrintFields();
}
public void PrintFields()
{
Console.WriteLine("x={0},y={1}", x, y);
}
}
class B : A
{
int x =2;
int y =2;
public B()
{
x = -2;
y = -2;
}
public void PrintFields()
{
Console.WriteLine("x={0},y={1}", x, y);
}
}
实例化子类,打印结果:
x=1,y=1
子类实例化构造函数先调用父类的构造函数,因为父类的字段声明时已赋值,所以字段先于父类的构造函数得到值,然后父类构造函数调用父类的方法(因为方法没有重写)。
关于静态构造函数 构造函数 重写 非重写 调用顺序的一点总结:
1.类中字段声明时直接赋值的,会先于构造函数(包括静态构造函数)执行。不论字段是否是静态。
2.类中静态构造函数先于构造函数执行。注意,静态构造函数不论类实例化多少次,仅执行一次。
3.实例化子类时,父类构造函数内有调用方法的,如果此方法没有重写,则调用父类的方法,并使用父类的字段。
如果此方法在子类有重写,则调用的是子类的方法,并使用子类的字段。
文字描述会比较绕口,建议大家动手测试一下。虽然平时基本不会遇到这样的问题,但实际测试还是会出乎大家意料的。