程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Emit學習(2),emit學習

Emit學習(2),emit學習

編輯:C#入門知識

Emit學習(2),emit學習


上周末回家去享受生活了, 工作是為了更好的生活嘛, 所以我把生活, 工作分的比較開. 這幾天不是很忙, 在學習工作技能的同時, 發點博文, 也算是做一個學習筆記

上篇中, 貼出的地址裡面那位哥, 也有一篇值類型和引用類型的文章

來源: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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved