.ctor,.cctor 以及 对象的构造过程
.ctor,.cctor 以及 对象的构造过程.ctor:简述:构造函数,在类被实例化时,它会被自动调用。当C#的类被编译后,在IL代码中会出现一个名为.ctor的方法,它就是我们的构造函数,对应C#中的构造函数。且看下面的代码: public class Class1 { private string name; private int age; }![]() 类Class1中没有显示的构造函数,只有两字段,现在用ILDasm.exe打开编译后生成的exe文件,会看到:
可以看到这里有个.ctor,我们没有定义构造函数,但这里却出现了.ctor,这就说明了: 当没有显示定义构造函数时,会自动生成一个构造函数,它没有参数,没有返回值。 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret 上面就是这个.ctor的方法体,看上面的红色行,从字面上可以看出,它是调用(call)了一个类型为System.Object的实例的.ctor()方法,从这就可以证明: 当一个类没有显示声明继承于其它某个类时,它将默认继承自System.Object,并且,在类的构造函数中将会调用其基类的构造方法(.ctor)。 public class Class1 { private string name = "Lin"; private int age; }![]() 再用ILDasm打开生成的exe文件,打开.ctor,里面有这么几行: IL_0000: ldarg.0 IL_0001: ldstr "Lin" IL_0006: stfld string ConsoleApplication1.Class1::name IL_000b: ldarg.0 IL_000c: call instance void [mscorlib]System.Object::.ctor() IL_0011: nop 这个跟刚才的相比,多出了红色的那两行,这两行出现在“调用System.Object的构造方法”之前,这说明: 如果在字段声明的同时对其初始化,那么在编译后,赋值过程将被放到构造方法.ctor中,并且在调用其基类的构造方法之前进行。 现在给上面的C#程序显式加上一个构造方法,它接受两个参数: public class Class1 { private string name = "Lin"; private int age;![]() public Class1(string name, int age) { this.name = name; this.age = age; } }![]() 再用ILDasm打开exe时,会发现有了点变化: 如果类中有显式定义构造方法,那么就不会再自动生成一个无参数无返回值的默认构造方法。 IL_0000: ldarg.0 IL_0001: ldstr "Lin" IL_0006: stfld string ConsoleApplication1.Class1::name IL_000b: ldarg.0 IL_000c: call instance void [mscorlib]System.Object::.ctor() IL_0011: nop IL_0012: nop IL_0013: ldarg.0 IL_0014: ldarg.1 IL_0015: stfld string ConsoleApplication1.Class1::name IL_001a: ldarg.0 IL_001b: ldarg.2 IL_001c: stfld int32 ConsoleApplication1.Class1::age IL_0021: nop 从上面红色标识的代码的顺序中,我们可以进一步得到: 如果在声明字段时同时对其赋值,那么这个赋值过程将在类型的构造方法(.ctor)中最先执行,然后再执行其基类的构造方法,最后才轮到我们显示定义的构造方法体中代码。 .cctor简述:类型初始化器,是一个静态方法,无参数无返回值,不能直接调用,最多只有一个我们现在先给刚才的代码加上一个静态字段: public class Class1 { private string name = "Lin"; public static int count = 50; private int age;![]() public Class1(string name, int age) { this.name = name; this.age = age; } }![]() 再来打开ILDasm来看看: IL_0000: ldc.i4.s 50 IL_0002: stsfld int32 ConsoleApplication1.Class1::count 它对静态字段count进行了赋值,值是50,那么,是.cctor先调用还是.ctor先调用呢?当然是.cctor,它是为初始化类型而生的,专搞静态的东东,而.ctor是构造方法,当然.cctor要先调用了。 现在显示加上一个.cctor,在C#中就是加个静态构造函数,我们不能为其指定访问修饰符(否则编译就会报错): public class Class1 { private string name = "Lin"; public static int count = 50; private int age;![]() static Class1() { count = 100; }![]() public Class1(string name, int age) { this.name = name; this.age = age; } }![]() 再来看看现在ILDasm下的.cctor,其中有几行: IL_0000: ldc.i4.s 50 IL_0002: stsfld int32 ConsoleApplication1.Class1::count IL_0007: nop IL_0008: ldc.i4.s 100 IL_000a: stsfld int32 ConsoleApplication1.Class1::count 可以看到: 在继承中对象构造过程看下面这段程序: public class A { public int x = 1; public A() { m1(); } public void m1() { } }![]() public class B : A { public int y = 2; public static string sb = "B"; public B() { m2(); } public void m2() { } }![]() public class C : B { public int z = 3; public static string sc = "C"; public C() { m3(); } public void m3() { } }![]() 编译后用ILDasm打开生成的exe文件: 可以看到三者都有一个.ctor,B、C中有.cctor,而A没有,打开B,C的.cctor,可以看到它们都负责初始化自己的静态字段,现在主要来看它们的.ctor。 先看类C的.ctor: IL_0001: ldc.i4.3 IL_0002: stfld int32 ConsoleApplication1.C::z IL_0007: ldarg.0 IL_0008: call instance void ConsoleApplication1.B::.ctor() IL_000d: nop IL_000e: nop IL_000f: ldarg.0 IL_0010: call instance void ConsoleApplication1.C::m3() 可以看到: 再来看类B的.ctor(): IL_0001: ldc.i4.2 IL_0002: stfld int32 ConsoleApplication1.B::y IL_0007: ldarg.0 IL_0008: call instance void ConsoleApplication1.A::.ctor() IL_000d: nop IL_000e: nop IL_000f: ldarg.0 IL_0010: call instance void ConsoleApplication1.B::m2() 同样,我们可以看到,在实例化B时,它会先把2赋给自己的y,然后再调用基类A的构造方法,最后再调用自己的实例方法m2()。 那A的.ctor()就不再看了,可以猜到它一定是在做这样的事: 总结1、.ctor是构造方法; 参考资料1、《Essential .NET》 Volume 1 原文:http://www.cnblogs.com/mouhong-lin/archive/2008/05/18/1201747.html |
.ctor,.cctor 以及 对象的构造过程的更多相关文章
- Java之对象构造过程
先来运行一段代码 class A { public A() { init(); } public void init() { } public static void main(String[] ar ...
- swift 学习- 16 -- 构造过程 02
// 类的继承 和 构造过程 // 类里面的所有的存储型属性 -- 包括所有继承自父类的属性 -- 都必须在构造过程中设置初始值 // Swift 为类类型提供了 两种构造器来确保实例中所有的存储属 ...
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- 从C++对象内存布局和构造过程来具体分析C++中的封装、继承、多态
一.封装模型的内存布局 常见类对象的成员可能包含以下元素: 内建类型.指针.引用.组合对象.虚函数. 另一个角度的分类: 数据成员:静态.非静态 成员函数:静态.非静态.虚函数 1.仅包含内建类型的场 ...
- Emit学习(2) - IL - 对象的创建过程
上一篇的介绍中, 并没有介绍到对象的创建过程, 这一篇主要就介绍一下, 对象的创建过程. 其实熟悉了IL语法之后, 完全可以用Reflector反编译代码去查看. 而且正因为有这个工具, 可以对照着R ...
- SICP— 第一章 构造过程抽象
SICP Structure And Interpretation Of Computer Programs 中文第2版 分两部分 S 和 I 第一章 构造过程抽象 1,程序设计的基本元素 2,过 ...
- swift学习笔记之-构造过程
//构造过程 import UIKit /* 构造过程(Initialization): 1.构造过程是使用类.结构体或枚举类型的一个实例的准备过程.在新实例可用前必须执行这个过程,具体操作包括设置实 ...
- JAVA 对象初始化的过程
对象初始化的过程例:Student S = new Student();1.因为new Student()用到了Student类,所以会把它从硬盘上加载进入内存2.如果有static静态代 ...
- C++ 构造过程和析构过程
1.C++构造和析构的过程,类似于穿衣脱衣的过程.穿衣是:先穿内衣,再穿外套.脱衣是:先脱外套,再脱内衣.C++构造过程:首先调用父类构造方法,再调用子类构造方法.C++析构过程:首先调用子类析构方法 ...
随机推荐
- Redis结合EntityFramework结合使用的操作类
最近一段时间在研究redis. 各种不懂, 各种问题.也看了N多的资料. 最终参照着 张占岭 的博客 http://www.cnblogs.com/lori/p/3435483.html 写 ...
- Jenkins 六: 构建中执行shell或者 windows的批处理程序
Shell/ bat Jenkins 可以在构建中执行shell命令或者windows的batch 命令. 1. 选择一个项目,点击“配置”. 2. 找到“构建” –> “增加构建步骤”.选择 ...
- Java 热部署深入探索
简介 在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加载才能完成更新操作.对于某些大型的 ...
- E - 食物链 poj1182
题目告诉有 3 种动物,互相吃与被吃,现在告诉你 m 句话,其中有真有假,叫你判断假的个数 ( 如果前面没有与当前话冲突的,即认为其为真话 ).每句话开始都有三个数 D A B,当D = ...
- B - Frogger
题目大意: 一个叫做弗雷迪的青蛙坐在湖中间的一块石头上.突然他注意到他的青蛙女神菲奥娜坐在另一块石头上面,于是他计划去看她,但是呢湖里面的水很脏并且充满了游客的防晒霜,所以他想避免游泳而采用跳跃的方式 ...
- 英蓓特Mars board的android4.0.3源码编译过程
英蓓特Mars board的android4.0.3源码编译过程 作者:StephenZhu(大桥++) 2013年8月22日 若要转载,请注明出处 一.编译环境搭建及要点: 1. 虚拟机软件virt ...
- tomcat不用工程名访问怎么配置?
tomcat不用工程名访问配置,直接用域名访问 在 tomcat6的安装路径下,D:\Tomcat-6\conf,修改server.xml文件 编辑Host节点, <Host appBase=& ...
- dubbo服务+Spring事务+AOP动态数据源切换 出错
1:问题描述,以及分析 项目用了spring数据源动态切换,服务用的是dubbo.在运行一段时间后程序异常,更新操作没有切换到主库上. 这个问题在先调用读操作后再调用写操作会出现. 经日志分析原因: ...
- Apache XAMPP Fails to start under Windows XP
Apache XAMPP Fails to start under Windows XP I’ve been installing XAMPP a hundred times before since ...
- Android Dialog透明度和暗度
1.设置透明度(Dialog自身的透明度)WindowManager.LayoutParams lp=dialog.getWindow().getAttributes(); lp.alpha=1.0f ...
public class Class1
{
private string name;
}
{
}

