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

  • 相关阅读:
    LeetCode题解之Flipping an Image
    LeetCode 之Find Minimum in Rotated Sorted Array
    LeetCode题解Transpose Matrix
    LeetCode 题解之Minimum Index Sum of Two Lists
    LeetCode题解之Intersection of Two Linked Lists
    LeetCode 题解之Add Two Numbers II
    LeetCode题解之Add two numbers
    href="#"与href="javascript:void(0)"的区别
    有关ie9 以下不支持placeholder属性以及获得焦点placeholder的移除
    ie7下属性书写不规范造成的easyui 弹窗布局紊乱
  • 原文地址:https://www.cnblogs.com/elvinle/p/6015097.html
Copyright © 2011-2022 走看看