zoukankan      html  css  js  c++  java
  • Emit学习(2)

    上周末回家去享受生活了, 工作是为了更好的生活嘛, 所以我把生活, 工作分的比较开. 这几天不是很忙, 在学习工作技能的同时, 发点博文, 也算是做一个学习笔记

    上篇中, 贴出的地址里面那位哥, 也有一篇值类型和引用类型的文章

    来源:http://www.cnblogs.com/yingql/archive/2009/03/23/1420026.html

    我这个和他的那个稍有不同, 各位看官, 请!

    一、示例

    public class Person
        {
            public string Name { get; set; }
    
            public int Age { get; set; }
        }
    
        class Program
        {
            private Random rand = new Random(DateTime.Now.Millisecond);
    
            private Person person = new Person { Name = "Elvin", Age = 26 };
    
            private string pro = "pro";
    
            private double dou = 3.14;
    
            static void Main(string[] args)
            {
                Console.WriteLine("Main");
                Console.ReadKey();
            }
        }

    反编译Program的构造函数, 代码如下:

    public Program()
    {
        this.rand = new Random(DateTime.Now.Millisecond);
        Person person = new Person {
            Name = "Elvin",
            Age = 0x1a
        };
        this.person = person;
        this.pro = "pro";
        this.dou = 3.14;
    }
    
        .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 3
        .locals init (
            [0] class ConsoleApplication3.Person person,
            [1] valuetype [mscorlib]System.DateTime time)
    
        L_0000: ldarg.0    //加载this, 是一个地址, 将this沉底, 为一会的this.rand = new Random()服务
    L_0001: call valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now() L_0006: stloc.1 //初始化time, 为当前时间 L_0007: ldloca.s time //加载time的地址, 为什么加载地址呢, 一会详细介绍, 容我卖个关子 (1) L_0009: call instance int32 [mscorlib]System.DateTime::get_Millisecond() //调用结构体Datetime的方法 L_000e: newobj instance void [mscorlib]System.Random::.ctor(int32) //new Random(), 将对象放入堆中, 然后把指向此对象的地址压栈 L_0013: stfld class [mscorlib]System.Random ConsoleApplication3.Program::rand //把刚刚得到的地址赋给rand, 实现this.rand = new Random()功能 L_0018: ldarg.0 //加载this地址,将this沉底, 为一会的this.person=person服务
    L_0019: newobj instance void ConsoleApplication3.Person::.ctor() //new Person() L_001e: stloc.0 //person = new Person(), 这里的person并不是this.person, 注意 L_001f: ldloc.0 //加载person, 为什么此处是用的ldloc, 而不是ldloca呢? 答案马上揭晓 L_0020: ldstr "Elvin" //加载 "Elvin" 字符串 L_0025: callvirt instance void ConsoleApplication3.Person::set_Name(string) //person.Name = "Elvin" L_002a: nop L_002b: ldloc.0 L_002c: ldc.i4.s 0x1a L_002e: callvirt instance void ConsoleApplication3.Person::set_Age(int32) L_0033: nop L_0034: ldloc.0 //加载person, 不是this.person L_0035: stfld class ConsoleApplication3.Person ConsoleApplication3.Program::person //给this.person赋值, this.person=person L_003a: ldarg.0 //加载this, 这里加载this做什么? (2) L_003b: ldstr "pro" //加载"pro"字符串 L_0040: stfld string ConsoleApplication3.Program::pro //this.pro = "pro" L_0045: ldarg.0 L_0046: ldc.r8 3.14 L_004f: stfld float64 ConsoleApplication3.Program::dou L_0054: ldarg.0 L_0055: call instance void [mscorlib]System.Object::.ctor() L_005a: nop L_005b: ret }

    例子大家应该都能看得懂, 下面就揭晓上面的包袱

    二、注意的点

    在揭晓答案之前, 首先得开一扇窗户.

    大家应该都知道, 值类型、引用类型是怎么存储的吧, 多的就不解释了, 上一幅图吧

    2. stfld -- 好吧, 在讲第1点之前, 我还是想先将第2点

    先看stfld的工作原理, 即堆栈转换行为如下:

    按照先后顺序:

      1.将一个对象引用或指针压入堆栈

      2.将值压入堆栈

      3.该值和对象的引用/指针从堆栈中弹出,对象的字段更新为替换的值

    详细分析 : http://www.cnblogs.com/jackson0714/p/4995948.html

    从上面可以看出, 是需要传地址的, 先传地址, 在传值, 接着调用stfld指令, 才能完成赋值操作, 所以这里传了个ldarg.0, 来完成this.pro="pro"功能

    1. ldloc 与 ldloca

    从上面的例子, 看到在使用Person的时候, 用的ldloc, 而使用DateTime的时候, 却使用了ldloca, 此处就能体现引用类型和值类型的区别了.

    在调用方法的时候, 由于引用类型在栈中, 存放的就是地址, 所以可以直接实现调用内部方法的功能, 

    而值类型并不是直接存放地址的, 所以在调用内部方法的时候, 其实是传地址来实现此功能的.

    对象,结构体(值类型本质也是结构体, 如:int, decimal)在调用自身方法/属性/字段的时候, 都是通过传递地址的方式来调用的. time.Year(), 此处的time就是地址, person.Name, 此处的person也是一个地址

     这哥们对IL有一个比较详细的介绍:http://www.cnblogs.com/jackson0714/p/DotNET_IL3.html#_label4

  • 相关阅读:
    体验cygwin纪实
    播布客视频PIT专用播放器MBOO2015
    rpm基本命令参考
    rhel7.x配置本地yum
    mtr网络连通性测试
    Oracle下载汇聚
    Spring Cloud心跳监测
    Hystrix的用法
    Redis系列十:缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
    dubbo异步调用三种方式
  • 原文地址:https://www.cnblogs.com/elvinle/p/6015097.html
Copyright © 2011-2022 走看看