C#在类型实例化时都干了什么:从一道笔试题说开去

发表于:2012-2-08 09:47

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:cyoooo7(cnblogs)    来源:51Testing软件测试网采编

  类似于上个例子里的MyClass,这里的子类Derived和基类Base都有静态构造函数,也包含静态和实例成员各一个。当实例化一个子类Derived对象的实例时,输出的结果可能并不容易想到:

派生类静态字段被实例化。
派生类静态构造函数被调用。
派生类实例成员字段被实例化。
基类静态字段被实例化。
基类静态构造函数被调用。
基类实例成员字段被实例化。
基类构造函数被调用。
派生类构造函数被调用。

  从结果我们可以看出,派生类的静态字段初始化,静态构造函数调用,实例成员字段初始化都会先于基类的任何初始化动作被执行。对于派生类静态部分先被构造这一点比较容易理解,因为毕竟在CLR装载派生类Derived之前,基类Base还未被使用过,也就不会先被装载。

  但是,为什么派生类的实例成员字段会在基类被构造之前被初始化呢?答案和虚函数有关。试想有这么一个基类,它在构造函数中调用了一个虚方法。然后又有这么一个派生类,它重写了基类的那个虚方法,并且在这个虚方法中访问了它自己的一个实例成员字段。这一切都是完全合法的(至少在C#的世界里是这样的),对吧?在实例化一个派生类对象的过程中,其基类的构造函数会被调用,接着那个虚方法也会被调用,再接着派生类的实例成员字段会被访问。所以此时此刻,这个类的实例成员字段必须是已被准备好了的!因此,派生类的实例成员字段必须先于基类部分被构造。

  好了,再回到我们的例子。剩下的部分很容易理解:基类按照我们预想的方式被生成,然后派生类的构造函数被调用。至此,一个派生类的对象就被实例化了。

  顺便说一句,关于类字段初始化器,或对象字段初始化器,他们初始化成员字段的顺序是成员在类定义中出现的先后顺序。再顺便说一句,如果程序的逻辑依赖于成员在类定义中出现的顺序则是不好的设计,这可能会大大降低您代码的易读性。

  现在当我们再回过头看文章开头的题目时,一切都明朗了——根本就没有一个正确答案!因为如果X类型有对象字段初始化器,且其构造函数内没有初始化任何实例字段的话,答案应该选B。如果X类型没有对象字段初始化器,且其构造函数内初始化了实例字段的话,答案选C。如果X类型没有对象字段初始化器,且其构造函数内没有初始化任何实例字段的话,答案选D。再其他的情况,则没有答案可选了。

22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号