这段时间忙的像狗一样,写博客的事情也就耽搁了,继续扯,为什么说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和explicitkeyword,这两个就是所谓的转换操作符,顾名思义,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 }
好了。我想你一切都清楚了,当我们在愉快的写着++,--的时候。殊不知编译器给我们做的太多太多,最后得要感谢一下编译器。