C#學(xué)習(xí)中,我們應(yīng)該都知道"+"號(hào)的使用方法,今天我們就來談一談它的使用,一般情況下認(rèn)為"+"操作符有兩種功能,一種是做算術(shù)加,一種是做字符串的連接。
今天看到一份文檔說,深入解析C#中兩個(gè)PLUS操作符執(zhí)行的不同操作,想了想,也的確應(yīng)該是這樣,IL代碼實(shí)例也表面這個(gè)觀點(diǎn)是正確的:
我們先寫一小段測(cè)試代碼: namespace MSILTest { class Program { static void Main(string[] args) { string a = "aaa"; string b = a + "bbb"; System.Console.WriteLine(b); int c = 1; int d = c + 1; System.Console.WriteLine(d); } } }
反編譯得到IL代碼:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 40 (0x28) .maxstack 2 .locals init ([0] string a, [1] string b, [2] int32 c, [3] int32 d) IL_0000: nop IL_0001: ldstr "aaa" IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldstr "bbb" IL_000d: call string [mscorlib]System.String::Concat(string, string) IL_0012: stloc.1 IL_0013: ldloc.1 IL_0014: call void [mscorlib]System.Console::WriteLine(string) IL_0019: nop IL_001a: ldc.i4.1 IL_001b: stloc.2 IL_001c: ldloc.2 IL_001d: ldc.i4.1 IL_001e: add IL_001f: stloc.3 IL_0020: ldloc.3 IL_0021: call void [mscorlib]System.Console::WriteLine(int32) IL_0026: nop IL_0027: ret } // end of method Program::Main
從上面的代碼中可以看到,在+連接字符串的時(shí)候,C#的Complier是把它轉(zhuǎn)換成為了帶兩個(gè)參數(shù)的Concat()函數(shù)。這個(gè)函數(shù)可以反編譯System.dll可以看到這個(gè)靜態(tài)的帶兩個(gè)參數(shù)的方法。
而+在handle兩個(gè)number的時(shí)候,是直接轉(zhuǎn)換成為add操作指令的。 這“兩個(gè)”操作指令,完全沒有一點(diǎn)相似的地方。所以,我們需要把這不同功能的兩個(gè)+當(dāng)成是兩個(gè)運(yùn)算符來看待。
同時(shí),我們還可以稍為引申一下,關(guān)于C#中的強(qiáng)制類型轉(zhuǎn)換: 大家看這一句: IL_0021: call void [mscorlib]System.Console::WriteLine(int32) 如果我們把 System.Console.WriteLine(d); 改成 System.Console.WriteLine(’\u0041’); 相應(yīng)的IL代碼就會(huì)轉(zhuǎn)變成為: IL_0020: ldc.i4.s 65 IL_0022: call void [mscorlib]System.Console::WriteLine(char)
由此我們可以得到結(jié)論: 強(qiáng)制類型轉(zhuǎn)換,只不過是調(diào)用了一些方法的不同的重載的方法,而這個(gè)值本身是沒有變的。
這個(gè)值在Stack的頂部,轉(zhuǎn)換前后都不變,只是編譯器來根據(jù)強(qiáng)制類型轉(zhuǎn)換相應(yīng)的代碼來選擇不同方法的不同的重載版本。
跟蹤堆棧頂部數(shù)值,得到的結(jié)果也支持我們的這個(gè)結(jié)論。
|