日期:2014-05-17  浏览次数:20935 次

C#类的成员初始化顺序

首先我们来看看引用类型的成员初始化过程

?? 我们来看一个例子吧

class Program
{
??? static void Main(string[] args)
??? {
??????? DriveB d = new DriveB();
??? }
}

class BaseA
{
??? static DisplayClass a = new DisplayClass("基类静态成员初始化");

??? DisplayClass BaseA_c = new DisplayClass("基类实例变量BaseA_c初始化");

??? public BaseA()
??? {
??????? Console.WriteLine("基类构造方法被调用");
??? }
}

class DriveB : BaseA
{
??? static DisplayClass DriveB_b = new DisplayClass("继承类静态成员DriveB_b初始化");

??? //static BaseA DriveB_a = new BaseA();

??? DisplayClass DriveB_c = new DisplayClass("继承类实例变量DriveB_c初始化");

??? public DriveB()
??? {
??????? Console.WriteLine("继承类构造方法被调用");
??? }
}
class DisplayClass
{
??? public DisplayClass(string diplayString)
??? {
??????? Console.WriteLine(diplayString);
??????? Console.WriteLine();
??? }
}
程序动行的结果是:
继承类静态成员DriveB_b初始化
继承类实例变量DriveB_c初始化
基类静态成员初始化
基类实例变量BaseA_c初始化
基类构造方法被调用
继承类构造方法被调用

得出初始化顺序结论:

1)继承类静态成员变量初始化
2)继承类实例变量初始化
3)基类静态静态成员变量初始化
4)基类实例变量初始化
5)基类构造方法调用
6)继承类构造方法调用。

??? 好像结果和JAVA的有点不一样啊, 有点混乱的感觉,搞不懂M$为什么要让初始化按这样的顺序执行,像JAVA那样严格的从基类到派生类多好呀.上例的运行结果说明, 构造函数这么这个和我们通常思路执行的顺序还是有一定的差别.对于实例成员初始化,基本上就是以下步骤执行:
1 类的对象初始化大体顺序上实例成员赋值到构造函数
2 成员赋值初始化按照由子类到父类的顺序
3 构造函数的初始化按照由父类到子类的顺序
从这里我们有一点需要注意的是,因为成员赋值初始化是从子类到父类的,所以在子类的成员赋值初始化的过程中,不要引用父类定义的成员,因为这个时候父类成员还没有开始初始化.需要说明一点的是C#在创建对象的第一步分配内存完成后会动把所有实例成员变量初始化成变量的默认值,例如整型就是0,引用类型就是null.然后才开始进行成员变量初始化的过程.

?

C#对象初始化

1.???? 先变量后构造函数。变量先被初始化,然后构造函数被执行

2.???? 先静态化后实例化。当一个类被访问时,静态变量和构造函数最先被初始化.接着是对象的实例化变量和构造函数被初始化

3.???? 先派生类后基类。对于变量和静态构造函数,派生对象在基对象之前被初始化.比如C类派生自B,B类派生自A,那么变量和静态构造函数被初始化次序是C-B-A.

4.???? 除了实例构造函数。对于实例构造函数,基类构造函数在派生类构造函数之前执行,实例构造函数被执行次序是A-B-C.

5.???? 不要假定变量的次序。Fields依据它们在源文件中的声明的顺序依次初始化.然而,自从程序员和工具可以随意安排变量的声明后,你不应该在依靠变量任何特别的次序初始化

6.???? 对虚方法用两个阶段的构建。避免从一个构造器调用虚方法. 如果在初始化一个对象时需要调用一些虚方法,应在完整构造该对象的地方使用两阶段的构建,并随后调用已构造对象的初始化方法。