上一篇的介绍中, 并没有介绍到对象的创建过程, 这一篇主要就介绍一下, 对象的创建过程.

其实熟悉了IL语法之后, 完全可以用Reflector反编译代码去查看. 而且正因为有这个工具, 可以对照着Reflecotr中的IL代码去写Emit的IL.

好了, 开始正题了, 还是从实例开始:

一、示例

首先建类(Person, Contacts):

public class Person
{
public string Name { get; set; } public int Age { get; set; } public Contacts Contact { get; set; } public override string ToString()
{
return string.Format("Name:{0}\r\nAge:{1}\r\nContact:{2}", this.Name, this.Age, this.Contact.ToString());
}
} public class Contacts
{
public string Address { get; set; } public string Phone { get; set; } public string QQ { get; set; } public override string ToString()
{
var res = string.Format(@"[Address:{0}, Phone:{1}, QQ:{2}]", this.Address, this.Phone, this.QQ);
return res;
}
}

然后就可以写创建方法了:

static void PersonTest()
{
var contacts = new Contacts { Address="HeFei", Phone="", QQ=""};
var person = new Person { Name = "Wubi", Age = , Contact = contacts };
Console.WriteLine(person.ToString());
}

反编译后的IL代码如下:

.method private hidebysig static void PersonTest() cil managed
{
.maxstack
.locals init (
[] class ConsoleApplication1.Contacts contacts,
[] class ConsoleApplication1.Person person,
[] class ConsoleApplication1.Contacts contacts2,
[] class ConsoleApplication1.Person person2) L_0000: nop
L_0001: newobj instance void ConsoleApplication1.Contacts::.ctor()
L_0006: stloc. L_0007: ldloc.
L_0008: ldstr "HeFei"
L_000d: callvirt instance void ConsoleApplication1.Contacts::set_Address(string) //contacts2.Address = "HeFei" L_0012: nop
L_0013: ldloc.
L_0014: ldstr ""
L_0019: callvirt instance void ConsoleApplication1.Contacts::set_Phone(string) L_001e: nop
L_001f: ldloc.
L_0020: ldstr ""
L_0025: callvirt instance void ConsoleApplication1.Contacts::set_QQ(string) L_002a: nop
L_002b: ldloc.
L_002c: stloc. //contacts = contacts2 L_002d: newobj instance void ConsoleApplication1.Person::.ctor()
L_0032: stloc.
L_0033: ldloc.
L_0034: ldstr "Wubi"
L_0039: callvirt instance void ConsoleApplication1.Person::set_Name(string) L_003e: nop
L_003f: ldloc.
L_0040: ldc.i4.s
L_0042: callvirt instance void ConsoleApplication1.Person::set_Age(int32) L_0047: nop
L_0048: ldloc.
L_0049: ldloc.
L_004a: callvirt instance void ConsoleApplication1.Person::set_Contact(class ConsoleApplication1.Contacts) L_004f: nop
L_0050: ldloc.
L_0051: stloc.
L_0052: ldloc. L_0053: callvirt instance string [mscorlib]System.Object::ToString()
L_0058: call void [mscorlib]System.Console::WriteLine(string)
L_005d: nop
L_005e: ret
}

二、补充的点

可能有人注意到了, 此处调用方法时, 用的并不是Call, 而是 Callvirt, 什么时候用Call, 什么时候用Callvirt呢?

首先, 我们看callvirt出现的位置, 是出现在public string Name{get;set;}中的, get, set其实是两个方法, 大家都知道的, 所以在给属性赋值时, 其实是调用的方法, 所以这里赋值并不是用的stloc之类的

.method public hidebysig specialname instance void set_Name(string 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
.maxstack
L_0000: ldarg. //非静态方法中, arg0指的是this
L_0001: ldarg. //arg1才是这里的'value'
L_0002: stfld string ConsoleApplication1.Person::<Name>k__BackingField
L_0007: ret
}

其次, 我们先从字面的意思去看着两个指令

Call 都知道是调用的意思, 那么Callvirt什么意思呢? 从前面的经验, 我想到, 这些指令并不是随便取的, 短到一个字母都是有特定意义的, 所以, 把Callvirt拆开来, 只看virt, 是不是有些熟悉的赶脚, 跟virtual这个单词比较一下, 就能明白Callvirt主要是调用那些方法了.

嘿嘿, 没有再次了哦, 下面是call和callvirt的一些区别:

1.call可以调用静态方法, 实例方法, 以及虚方法; 而callvirt只能调用实例方法和虚方法, 对于静态方法, 是心有余而力不足的

2.call一般是以非虚的方法来调用函数的, 而callvirt是以多态的方式来调用函数的.

至于异同的实例, 我就不给了, 大家可以看一下 : http://www.cnblogs.com/wang_yb/archive/2011/06/28/2092327.html

还有一个哥们也写过call与callvirt的区别 : http://www.cnblogs.com/yingql/archive/2009/03/23/1420000.html

网络时代就是好啊, 可以很容易的就能获取到别人的成果, 谢谢这些哥们了

Emit学习(2) - IL - 对象的创建过程的更多相关文章

  1. 图解JAVA对象的创建过程

    前面几篇博文分别介绍了JAVA的Class文件格式.JVM的类加载机制和JVM的内存模型,这里就索性把java对象的创建过程一并说完,这样java对象的整个创建过程就基本上说明白了(当然你要有基础才能 ...

  2. HttpApplication 对象的创建过程及HttpModule过滤器的内部实现过程

    最近通过Reflector学习了一下asp.net内部的原理,做做笔记,方便以后查阅. 先看下HttpApplication 对象的创建过程 从IHttpHandler applicationInst ...

  3. JVM中对象的创建过程

    JVM中对象的创建过程如以下流程图中所示: 对其主要步骤进行详细阐述: 为新生对象分配内存: 内存的分配方式: 指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存在另一边, ...

  4. 对象的创建过程(chapter5.7.3)

    总结一下对象的创建过程,假设有一个名为Dog的类: 1. 即使没有显示地使用static关键字,构造器实际上也是静态的方法,因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类 ...

  5. 2 Java对象的创建过程

    JAVA中创建对象直接new创建一个对象,对么对象的创建过程是怎样的呢? 程序运行过程中有许多的对象被创建出来.那么对象是如何创建的呢? 一 对象创建的步骤 1 遇到new指令时,检查这个指令的参数是 ...

  6. 深入理解Java对象的创建过程:类的初始化与实例化

    摘要: 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类 ...

  7. JAVA虚拟机:对象的创建过程

    简要说明的话,Java对象的创建过程分为下面几步: 1.执行相关检查: 2.为对象分配内存,将分配到的内存空间都初始化为零值: 3.进行构造代码块和构造函数的初始化 下面详细介绍这几个步骤: 1.执行 ...

  8. java中对象的创建过程

    public class Test1 { public static void main(String[] args) { new B(); System.out.println("---- ...

  9. 类加载过程&对象的创建过程

    类加载过程 1.JVM发现要使用一个类,首先要到方法区中找:如果找到了,就直接使用,如果没有找到,才会去找这个类的class文件,然后加载: (在找class文件时,是根据classpath配置的地址 ...

随机推荐

  1. [.net 面向对象编程基础] (13) 面向对象三大特性——多态

    [.net 面向对象编程基础] (13) 面向对象三大特性——多态 前面两节,我们了解了面向对象的的封装和继承特性,面向对象还有一大特性就是多态.比起前面的封装和继承,多态这个概念不是那么好理解.我们 ...

  2. python--同一mysql数据库下批量迁移数据

    最近接手些mysql数据库维护,发现mysql在批量操作方面就是个渣渣啊,比起MS SQL SERVER简直就是“不可同日而语”. 咨询了下MySQL的高手,对于数据迁移这种问题,一种处理方式就是直接 ...

  3. DNS拾遗(一)

    最近帮朋友注册域名配置主机,碰到一些DNS上的一些概念,惭愧于有一些东西已经忘记是啥意思,于是决定重新学习一下DNS方面的基本概念. 常用概念: TTL: TTL为Time to live的缩写,网络 ...

  4. [nRF51822] 4、 图解nRF51 SDK中的Schedule handling library 和Timer library

    :nRF51822虽然是一个小型的单片机,但是能真正达到任意调用其官方驱动以及BLE协议栈的人还是奇缺的.据我所见,大都拿官方给的一个冗长的蓝牙低功耗心率计工程改的.之前我对于这个工程进行log跟踪, ...

  5. C-Lodop 非典型应用

    Lodop是什么? 有人说她是报表打印工具,因为那个add_print_table语句把报表统计的那点事弄了个明明白白: 有人说她是条码打印工具,因为用了她再也不用后台生成条码图片了,前端一行指令就动 ...

  6. 为什么占位符可以防止sql注入?

    先看下面用占位符来查询的一句话 String sql = "select * from administrator where adminname=?"; psm = con.pr ...

  7. PHP面向对象07_PDO

    oop007复习 2014-9-4 9:42:28 摘要: 1.pdo的作用 2.pdo的安装 3.pdo连接属性设置 4.pdo对象和PDOStatement对象 5.pdo预处理 6.pdo事务机 ...

  8. Atitit  DbServiceV4qb9 数据库查询类库v4 新特性

    Atitit  DbServiceV4qb9 数据库查询类库v4 新特性     V4新特性 安全特性,屏蔽了executeUpdate,使用v2版 Sql异常转换,特别转换了DuplicateEnt ...

  9. 在同一台电脑上同时安装Python2和Python3

    目前Python的两个版本Python2和Python3同时存在,且这两个版本同时在更新与维护. 到底是选择Python2还是选择Python3,取决于当前要使用的库.框架支持哪个版本. 例如:HTM ...

  10. 批处理集锦——(5)使用dir查找文件

    eg dir /a-d /s /b *.bat -d表示不显示.bat结尾的文件夹