博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 小测试(一):类成员初始化与构造函数执行的顺序
阅读量:7067 次
发布时间:2019-06-28

本文共 2054 字,大约阅读时间需要 6 分钟。

看看下面这段代码,你觉得它会输出什么呢?

class Foo
{
public Foo(string s)
{
Console.WriteLine("Foo constructor: {0}", s);
}
 
public void Bar(){}
}
 
class Base
{
readonly Foo baseFoo = new Foo("Base initializer");
public Base()
{
Console.WriteLine("Base constructor");
}
}
 
class Derived : Base
{
readonly Foo derivedFoo = new Foo("Derived initializer.");
public Derived()
{
Console.WriteLine("Derived constructor");
}
}
 
class Program
{
static void Main(string[] args)
{
new Derived();
}
}

先猜一下吧,似乎应该是“Base initializer, Base constructor, Derived initializer, Derived constructor”。

事实上,应当是先执行类成员的初始化,顺序是从derived到base,然后是两个构造函数,顺序是从base从derived。

这种方式是很有意义的,在类继承体系中层次较深的类(离System.Object较远)将依赖于较浅的类(离System.Object较近)。但是很多人会相信调用的顺序应当等价于下面的伪代码:

// 期望的顺序
BaseConstructor()
{
ObjectConstructor();
baseFoo = new Foo("Base initializer");
Console.WriteLine("Base constructor");
}
DerivedConstructor()
{
BaseConstructor();
derivedFoo = new Foo("Derived initializer");
Console.WriteLine("Derived constructor");
}

而实际情况则是:

// 实际的顺序
BaseConstructor()
{
baseFoo = new Foo("Base initializer");
ObjectConstructor();
Console.WriteLine("Base constructor");
}
DerivedConstructor()
{
derivedFoo = new Foo("Derived initializer");
BaseConstructor();
Console.WriteLine("Derived constructor");
}

那么,这样处理是为什么呢?

...

...

...

我们来看一下,如果代码按期望的顺序(第一段伪代码)执行,会产生什么问题:

class Base
{
public Base()
{
Console.WriteLine("Base constructor");
if (this is Derived) (this as Derived).DoIt();
// 如果是在创建Derived类的实例,就会遭遇null。
Blah();
// 如果是在创建MoreDerived类的实例,就会遭遇null。
}
 
public virtual void Blah() { }
}
 
class Derived : Base
{
readonly Foo derivedFoo = new Foo("Derived initializer");
public DoIt()
{
derivedFoo.Bar();
}
}
 
class MoreDerived : Derived
{
public override void Blah() { DoIt(); }
}

看Base类的构造函数,如果按期望的顺序执行,那么在Base方法执行时,Derived类的实例成员并没有得到初始化,此时就会有NullReference异常了。

而按照实际执行的顺序,所有的实例成员都能确保被完整地初始化:)

当然了,如果readonly字段是在构造函数中进行的,那么上面的确保机制就不复存在了。

参考:

 

本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2008/07/12/Why-Do-Initializers-Run-In-The-Opposite-Order-As-Constructors.html,如需转载请自行联系原作者。

你可能感兴趣的文章
Java基本问题
查看>>
Hexo搭建GitHub博客—打造炫酷的NexT主题--高级(三)
查看>>
内部技术分享PPT ------ “小程序入门”
查看>>
一款小程序增强开发工具 - EWA
查看>>
基于vue2.X的webpack基本配置(手动版~)
查看>>
观察者模式
查看>>
《Thinking in Android》 - 博客索引(Android 9.0)
查看>>
【开源】Tsar——灵活的系统和应用采集软件
查看>>
async/await 并行请求和错误处理
查看>>
深入浅出 Node ( 二 ) 模块机制
查看>>
【跃迁之路】【493天】刻意练习系列252(2018.06.13)
查看>>
TiDB 在威锐达 WindRDS 远程诊断及运维中心的应用
查看>>
安装 VMware workstation
查看>>
javascript 判断是否为数组 isArray()
查看>>
php脚本开发Alfred workflow
查看>>
scrapy-redis分布式爬虫框架详解
查看>>
golang 的channels 行为
查看>>
Visual Studio Code 断点调试 Vue
查看>>
checkbox jquery 全选反选
查看>>
非专业游戏CPU多核性能研究
查看>>