這段時間忙的像狗一樣,寫部落格的事情也就耽擱了,繼續扯,為什麼說decimal神奇呢,大家都知道decimal是基元型別,但是
這個decimal型別在IL中居然沒有相應的IL指令,也就是說CLR根本不認識decimal,全是編譯器這一層在糊弄我們。
話不多說,看下最simple的例子,(加了點註釋方便理解)
1 static void Main(string[] args) 2 { 3 //居然呼叫了有參建構函式 4 decimal d = 1; 5 6 //直接將常量10推送到計算堆疊,然後將10放入區域性變數索引為1的位置,也就是i 7 int i = 10; 8 9 //居然呼叫了隱式轉換操作符,IL中就是呼叫相應的方法 10 d = i; 11 12 //居然呼叫了顯式轉換操作符,IL中就是呼叫相應的方法 13 i = (int)d; 14 }
從IL中可以看到,對decimal的所有操作最後玩的都是方法,對編譯器上層的我們而言卻一無所知,那麼下一個問題來了,這些
都是怎麼做到的呢?
一:decimal原始碼
當我們對decimal的實現充滿好奇心的時候,最滿足的方式的就是看原始碼了,大家應該都有對新鮮事物的好奇心,不管看不看
得懂都得裝X看。
1:implicit/explicit 操作符
從下面的IL中我們看到了這些亂七八槽的操作符,可能我們用的比較少或者有些人都沒看過,不過終有它的用武之地。
結合上面的IL程式碼,我們發現了implicit和explicit關鍵字,這兩個就是所謂的轉換操作符,顧名思義,implicit就是所謂的隱式轉換
操作符,explicit是顯式轉換了,再結合上面的IL程式碼,我們會發現給我們最終生成的是op_Implicit 和 op_Explicit方法。
可能有些人看不明白了,那我就舉個例子吧。
1 public class Program 2 { 3 static void Main(string[] args) 4 { 5 //這裡就是語法糖,c=10 最終呼叫的就是:隱式轉換呼叫 6 Complex c = 10; 7 8 //語法糖,(int)最終呼叫的是:顯式轉換呼叫 9 int j = (int)c; 10 } 11 } 12 13 public struct Complex 14 { 15 public Complex(int num) { } 16 17 /// <summary> 18 /// 隱式轉換呼叫的方法 19 /// </summary> 20 /// <param name="value"></param> 21 /// <returns></returns> 22 public static implicit operator Complex(int value) 23 { 24 return new Complex(value); 25 } 26 27 /// <summary> 28 /// 強制轉換呼叫的方法 29 /// </summary> 30 /// <param name="value"></param> 31 /// <returns></returns> 32 public static explicit operator int(Complex value) 33 { 34 return Convert.ToInt32(value); 35 } 36 }
從我的sample和IL中看,我想你應該清楚了,為了方便我們編碼效率以及更好的讓人理解,C#提供了這麼個好玩的語法糖,清晰明瞭。
2:op_*** 過載操作符
既然是基元型別就避免不了大量的算術運算和比較元算,那這些decimal又是如何做到的?還是繼續在原始碼裡面找找。
從原始碼裡面可以看到,原來C#用operator過載運算子對我們這個++,--,!=,<= 進行了過載,和轉換運算子一樣,最終
在IL層也是轉換為各種方法。
還是看個例子:
1 static void Main(string[] args) 2 { 3 decimal i = 10; 4 5 decimal j = 12; 6 7 var r1 = i > j; 8 9 var r2 = i == j; 10 }
好了,我想你一切都清楚了,當我們在愉快的寫著++,--的時候,殊不知編譯器給我們做的太多太多,最後得要感謝一下編譯器。