以前自己对这方面的内容一直比较模糊,只是知道一个大概的顺序,具体确切的执行顺序不能确定,于是抽空做了一个详细的测试,对其进行一番研究.
具体的程序代码比较简单,如下所示.
三个类分开来写的,一个父类,一个子类,一个测试类:
父类:
using System;
namespace TestInherit
{
public class Father
{
public int father_a=111;
public int father_aa=1111;
public readonly int father_c=7777;
public static int father_e=222;
public static int father_ee;
static Father()
{
father_e=5555;
father_ee=3333;
}
public Father()
{
father_ee=4444;
}
public Father(int a)
{
father_a=a;
}
}
}
子类:
using System;
namespace TestInherit
{
public class Son:Father
{
public int son_int=9999;
public static int son_b=111;
public static int son_c;
public Son()
{
son_c=222;
}
static Son()
{
son_c=333;
}
public Son(int a)
{
son_int=a;
}
}
}
测试类:
using System;
namespace TestInherit
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Son son1=new Son ();
}
}
}
然后一路F11,进行跟踪,可以得到完整的执行顺序如下所示:
- 子类静态变量;
- 子类静态构造函数;
- 子类非静态变量;
- 父类静态变量;
- 父类静态构造函数;
- 父类非静态变量;
- 父类无参构造函数;
- 子类无参构造函数;
提供的代码中,执行顺序是根据C#语言规范的定义来进行的,而不是所谓的“优先”来执行的。让我们来具体分析一下执行过程:
-
子类静态变量和静态构造函数:
son_b
和son_c
是子类Son
的静态变量,在类第一次被使用时进行初始化。son_c
的初始化是在静态构造函数中完成的。- 执行
static Son()
,因此son_c
被设置为 333。
-
子类非静态变量:
son_int
是子类Son
的非静态变量,会在实例化对象时进行初始化。- 实例化
Son
对象时,执行Son son1 = new Son();
,son_int
被设置为9999。
-
父类静态变量和静态构造函数:
father_e
和father_ee
是父类Father
的静态变量,在类第一次被使用时进行初始化。father_ee
的初始化是在静态构造函数中完成的。- 执行
static Father()
,因此father_e
被设置为 5555,father_ee
被设置为 3333。
-
父类非静态变量:
father_a
,father_aa
, 和father_c
是父类Father
的非静态变量,会在实例化对象时进行初始化。- 执行
Father()
构造函数,因此father_a
被设置为111,father_aa
被设置为1111,father_c
被设置为 7777。
-
父类无参构造函数:
- 执行
Father()
构造函数体,因此father_ee
被覆写设置为 4444。
- 执行
-
子类无参构造函数:
- 执行
Son()
构造函数体,son_c
被覆写成222。
- 执行
所以,子类非静态变量并没有“优先”于父类无参构造函数,而是在实例化子类对象时按照语言规范的定义进行的初始化顺序。
如果Main()
方法中改为Son son1=new Son (111)
,顺序为;
- 子类静态变量;
- 子类静态构造函数;
- 子类非静态变量;
- 父类静态变量;
- 父类静态构造函数;
- 父类非静态变量;
- 父类无参构造函数;
- 子类有参构造函数;
如果子类的有参构造函数改为:
public Son(int a):base(a)
{
son_int=a;
}
则顺序又有所改变:
- 子类静态变量;
- 子类静态构造函数;
- 子类非静态变量;
- 父类静态变量;
- 父类静态构造函数;
- 父类非静态变量;
- 父类有参构造函数;
- 子类有参构造函数;
以上测试改为父类声明,子类实现,结果也是一样,即main()
方法中改为Father son1=new Son ();
最后作一个总结:
1.一般原理是被依赖的先构造,依赖于人的后构造(PS:在面向对象的继承关系中,父类的构造函数会在子类的构造函数之前执行,确保被依赖的先构造。),c#
中是同层依赖(成员变量,其他的类变量等)优先于跨层依赖(父子关系)构造(注意java中正好相反);(子类的变量是不是可以理解为同层的依赖呢??)
2.静态构造函数,静态参数都是优先于非静态构造函数,非静态参数构造或初始化;
C#构造函数的执行顺序
构造函数的作用是初始化一个新对象,构造函数实在对象初始化的时候优先调用。readonly
字段可以直接在定义中进行赋值,也可在构造函数中对其进行赋值,其他地方不能对其进行赋值。
构造函数的执行顺序:如下
public class MyBaseClass
{
public MyBaseClass()
{
}
public MyBaseClass(int i)
: this()
{
}
public MyBaseClass(int i, int j)
{
}
}
public class MyDrivedClass : MyBaseClass
{
public MyDrivedClass()
: base(0)
{
}
public MyDrivedClass(int i)
{
}
public MyDrivedClass(int i, int j)
: base(i)
{
}
}
class Program
{
static void Main(string[] args)
{
//执行顺序System.Object()->MyBaseClass()->MyBaseClass(int i)->MyDrivedClass()
//MyDrivedClass md = new MyDrivedClass();
//执行顺序System.Object()->MyBaseClass()->MyDrivedClass(int i)
//int i = 0;
//MyDrivedClass md = new MyDrivedClass(i);
//若要不执行默认构造函数,需要添加继承base(canshu)或this(canshu)
//执行顺序System.Object()->MyBaseClass()->MyBaseClass(int i)->MyDrivedClass(int i, int j)
MyDrivedClass mdc = new MyDrivedClass(7, 8);
}
}
base
关键字是指向的基类构造方法,this
关键字是指向本类的构造方法。