C# 构造函数调用顺序
了解C#的一个类的加载过程,对于语言机制的理解和写出高效的语言很有帮助,这里简单介绍一下类的实例的构造函数调用过程。
C#类的实例的构造过程是,先为实例的数据字段分配内存,并对所有字段按字节置零(0或者null);然后初始化附加内存(类型对象指针和同步块索引);调用类型的实例构造器(也就是new关键字调用的普通构造函数)初始化字段。
假如有两个类:基类BaseClass和派生类DerivedClass。DerivedClass继承BaseClass。
namespace GenericSyntax.Constructor
{
class BaseClass
{
public BaseClass()
{
Console.WriteLine("Base class Ctor.");
}
} class DerivedClass:BaseClass
{
private string m_Var1 = "Assigned in declaration.";
private string m_Var2;
public DerivedClass()
{
Console.WriteLine(m_Var2==null);
Console.WriteLine(m_Var1);
m_Var1 = "Assigned in constructor of derived Class.";
Console.WriteLine("Derived class Ctor.");
}
public override string ToString()
{
return m_Var1;
}
}
}
namespace GenericSyntax
{
class Program
{
static void Main(string[] args)
{
TestCtor();
Console.ReadKey();
}
private static void TestCtor()
{
Constructor.DerivedClass instance = new
Constructor.DerivedClass();
Console.WriteLine(instance.ToString());
}
}
}
生成的BaseClass的IL和DerivedClass的IL如下:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代码大小 20 (0x14)
.maxstack
IL_0000: ldarg.
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldstr "Base class Ctor."
IL_000d: call void [mscorlib]System.Console::WriteLine(string)
IL_0012: nop
IL_0013: ret
} // end of method BaseClass::.ctor
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// 代码大小 69 (0x45)
.maxstack
IL_0000: ldarg.
IL_0001: ldstr "Assigned in declaration."
IL_0006: stfld string GenericSyntax.Constructor.DerivedClass::m_Var1
IL_000b: ldarg.
IL_000c: call instance void GenericSyntax.Constructor.BaseClass::.ctor()
IL_0011: nop
IL_0012: nop
IL_0013: ldarg.
IL_0014: ldfld string GenericSyntax.Constructor.DerivedClass::m_Var2
IL_0019: ldnull
IL_001a: ceq
IL_001c: call void [mscorlib]System.Console::WriteLine(bool)
IL_0021: nop
IL_0022: ldarg.
IL_0023: ldfld string GenericSyntax.Constructor.DerivedClass::m_Var1
IL_0028: call void [mscorlib]System.Console::WriteLine(string)
IL_002d: nop
IL_002e: ldarg.
IL_002f: ldstr "Assigned in constructor of derived Class."
IL_0034: stfld string GenericSyntax.Constructor.DerivedClass::m_Var1
IL_0039: ldstr "Derived class Ctor."
IL_003e: call void [mscorlib]System.Console::WriteLine(string)
IL_0043: nop
IL_0044: ret
} // end of method DerivedClass::.ctor
可以看出,则初始化DerivedClass时,DerivedClass的构造函数的IL代码顺序执行如下
1. 解析派生类实例字段的直接赋值语句,即:如果字段有直接赋值语句,则用该赋值语句或者字面量对字段进行赋值。
2. 调用基类的构造函数(逐级向上调用,知道Object的构造函数),基类的实例化过程同理。
3. 执行派生类该实例构造函数的函数体。
执行代码如下:
C# 构造函数调用顺序的更多相关文章
- java初始化构造函数调用顺序
类初始化时构造函数调用顺序: (1)初始化对象的存储空间为零或null值: (2)调用父类构造函数: (3)按顺序分别调用类成员变量和实例成员变量的初始化表达式: (4)调用本身构造函数. 例子 ...
- C++派生类构造函数调用顺序(详解)
我们来看下面一段代码: class B1 { public: B1(int i) {cout<<"constructing B1 "<<i<<e ...
- JAVA & .NET创建对象构造函数调用顺序
JAVA 定义Person类 package models; public class Person { public Person() { System.out.println("pe ...
- C++ 全局构造函数调用的顺序
C++的全局类和静态类的构造函数是在main函数之前调用的.但是,不同的类的构造函数以什么顺序调用呢? 对于g++编译器来说,这个顺序是由链接时,文件顺序决定的. 我们用一个例子来说明这一点. 我们有 ...
- c++深/浅拷贝 && 构造函数析构函数调用顺序练习题
1.深/浅拷贝 编译器为我们提供的合成拷贝构造函数以及合成的拷贝赋值运算符都是浅拷贝.浅拷贝只是做简单的复制,如果在类的构造函数中new出了内存,浅拷贝只会简单的复制一份指向该内存的指针,而不会再开辟 ...
- [Effective JavaScript 笔记]第18条:理解函数调用、方法调用及构造函数调用之间的不同
面向对象编程中,函数.方法.类的构造函数是三种不同的概念. JS中,它们只是单个构造对象的三种不同的使用模式. 三种不同的使用模式 函数调用 function hello(username){ ret ...
- C++中构造函数调用构造函数
今天想做道矩阵的题目时,却卡在一些编程细节上了,找了好久才发现原来是在构造函数处出了问题,然后上网百度了下,发现这篇文章说得很好:从一道题谈C++中构造函数调用构造函数,很棒! 还补充一点: 看来自己 ...
- 你不知道的JavaScript--Item8 函数,方法,构造函数调用
1.函数调用 Function绝对是JavaScript中的重中之重.在JavaScript中,Function承担了procedures, methods, constructors甚至是class ...
- C++类中一个构造函数调用另一个构造函数
class A { int a; int b; int c; public: A(int aa, int bb) : a(aa), b(bb),c(0) { cout << "a ...
随机推荐
- [设计模式]State模式
<Java与模式> 又称状态对象模式.状态模式是对象的行为模式.GOF95 一个对象的行为取决于一个或者多个动态变化的属性,这样的属性叫做状态.这样的对象叫做有状态的对象(stateful ...
- [Python] Send emails to the recepients specified in Message["CC"]
Recently, I'm working on a small program which needs to send emails to specific accounts. When I wan ...
- s5_day7装饰器作业
# 一:编写函数,(函数执行的时间是随机的) import time import random # def foo(): # time.sleep(random.randrange(1,5)) # ...
- 一行代码实现笔记本跳过微信认证连接WIFI
一行代码实现笔记本跳过微信认证连接WIFI 本文作者原创,没有参考其他文章,方法很简单但是很实用,转载请注明出处,谢谢! 问题 有一些WIFI需要通过微信认证才能连接,手机当然是可以的,但是我们手头的 ...
- HDU - 6321 Problem C. Dynamic Graph Matching (状压dp)
题意:给定一个N个点的零图,M次操作,添加或删除一条边,每一次操作以后,打印用1,2,...N/2条边构成的匹配数. 分析:因为N的范围很小,所以可以把点的枚举状态用二进制表示集合.用一维数组dp[S ...
- JAVA实现redis超时失效key 的监听触发
过期事件通过Redis的订阅与发布功能(pub/sub)来进行分发. 而对超时的监听呢,并不需要自己发布,只有修改配置文件redis.conf中的:notify-keyspace-events Ex, ...
- Tomcat 源码分析(转)
本文转自:http://blog.csdn.net/haitao111313/article/category/1179996 Tomcat源码分析(一)--服务启动 1. Tomcat主要有两个组件 ...
- Forward Proxy vs Reverse Proxy
Overview We've talked about reverse proxy servers and how they can really be good at protecting the ...
- 轮询、长轮询、长连接、socket连接、WebSocket
轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源.(而每一次的 HTTP 请求和应答 ...
- Python3.x: pyodbc+FreeTDS+UinxODBC连接sybase数据库(Linux系统)
Python3.x: pyodbc+FreeTDS+UinxODBC连接sybase数据库(Linux系统) 一.安装UinxODBC以及依赖包 yum -y install gcc gcc-c++ ...