.NET,你忘記了嗎?(七)—— 從a?b:c談起

來源:互聯網
上載者:User

1.  摘要

在這篇文章中,我會通過IL去分析一個簡單的語句。

如果覺得實在簡單,可以略過。

2.  引子

事情是這樣的,同事寫了一段類似這樣的代碼:

class Program{      static void Main(string[] args)      {            object o = new object();            int i;            Int32.TryParse(Console.ReadLine(), out i);            o = i > 3 ? null : 3.5;      }}

當然不是在控制台程式中,我在這裡只是寫出個類比。

然後系統報出了一個這樣的錯誤。

3. 錯誤分析

同事很詫異地問我,這是為什麼啊?

他給出的理由是object是一切類的父類,那麼我把3.5或者null賦給他都沒有問題啊,那這個問題是怎麼回事呢?

我意識到自己的語言表達能力遠不如代碼有說服力,於是,寫段代碼,然後請出IL。

4. 請出IL

讓我們先寫段正確的代碼,保證他的編譯通過。

class Program{      static void Main(string[] args)      {            object o = new object();            int i = 1;            int j = 2;            o = i+j > 3 ? 3 : 3.5;      }}

然後去查看IL代碼:

.method private hidebysig static void Main(string[] args) cil managed{      .entrypoint      .maxstack 2      .locals init (      [0] object o,      [1] int32 i,      [2] int32 j)      L_0000: nop      L_0001: newobj instance void [mscorlib]System.Object::.ctor()      L_0006: stloc.0      L_0007: ldc.i4.1      L_0008: stloc.1      L_0009: ldc.i4.2      L_000a: stloc.2      L_000b: ldloc.1      L_000c: ldloc.2      L_000d: add      L_000e: ldc.i4.3      L_000f: bgt.s L_001c      L_0011: ldc.r8 3.5      L_001a: br.s L_0025      L_001c: ldc.r8 3      L_0025: box float64      L_002a: stloc.0      L_002b: ret}

在這裡,我們只關注從L_00d開始的代碼,首先我們將兩個數i和j相加,然後去與3比較大小,如果大於3,那麼便跳轉到L_001c,將3作為Float類型壓棧,否則順序向下執行,將3.5作為float類型壓棧。最後將棧頂元素裝箱。

看過了這個解釋,我們再回去看原有的那段代碼,原因再清楚不過了,?:這個三元運算子在編譯成IL代碼時,把:兩端的值壓棧,然後把這兩個值儲存在一個臨時變數裡,而這個變數要取兩者之前類型轉換後級數最高的類型。舉個例子:int 和 float 就需要轉換成float,float 和 double 就需要轉換成double 等等。而在同事的程式中, double 類型和 null 類型無法相互轉換,所以就報了這樣的一個錯誤。

5. 改造代碼

繼續仔細思考,究竟什麼樣的兩個類型可以寫在:的兩端。上面的錯誤再清楚不過。兩個可以隱式轉換的類型可以。

那下面繼續解決這個問題。上面的代碼我們要怎麼寫:

static void Main(string[] args){      object o = new object();      int i;      Int32.TryParse(Console.ReadLine(), out i);      if (i > 3)      {            o = null;      }      else      {            o = 3.5;      }}

怎麼看都沒有上面的代碼漂亮。這個可以說除了能運行外真的沒什麼優點了。

還記得那個泛型類吧:Nullable<T>。

那就讓我們用這個泛型類來改造吧:

static void Main(string[] args){      object o = new object();      Nullable<double> n = 3.5;      int i;      Int32.TryParse(Console.ReadLine(), out i);      o = i > 3 ? null : n;}

如果覺得Nullable<T>還不夠美觀。

static void Main(string[] args){      object o = new object();      double? n = 3.5;      int i;      Int32.TryParse(Console.ReadLine(), out i);      o = i > 3 ? null : n;}

這樣改造是不是優秀了一些呢?

這個時候如果有人提出,那麼我為什麼不o=i>3?null:(object)3.5呢?那我們想一下如果有一天我們不再用object o;

我們是不是可以把代碼寫成這樣:

static void Main(string[] args){    //object o = new object();    double? o;    double? n = 3.5;    int i;    Int32.TryParse(Console.ReadLine(), out i);    o = i > 3 ? null : n;}

ShadowK 給出了這樣的做法,是個好辦法:

o = i > 3 ? (double?)null : n ;  

這個時候再看IL,是不是已經沒有了可惡的box呢?

.method private hidebysig static void Main(string[] args) cil managed{    .entrypoint    .maxstack 2    .locals init (        [0] valuetype [mscorlib]System.Nullable`1<float64> o,        [1] valuetype [mscorlib]System.Nullable`1<float64> n,        [2] int32 i,        [3] valuetype [mscorlib]System.Nullable`1<float64> CS$0$0000)    L_0000: nop     L_0001: ldloca.s n    L_0003: ldc.r8 3.5    L_000c: call instance void [mscorlib]System.Nullable`1<float64>::.ctor(!0)    L_0011: nop     L_0012: call string [mscorlib]System.Console::ReadLine()    L_0017: ldloca.s i    L_0019: call bool [mscorlib]System.Int32::TryParse(string, int32&)    L_001e: pop     L_001f: ldloc.2     L_0020: ldc.i4.3     L_0021: bgt.s L_0026    L_0023: ldloc.1     L_0024: br.s L_002f    L_0026: ldloca.s CS$0$0000    L_0028: initobj [mscorlib]System.Nullable`1<float64>    L_002e: ldloc.3     L_002f: stloc.0     L_0030: ret }

6. 總結

寫上面的文章我並不是單純地想闡明這個具體的文法情況。而是希望大家掌握一種思路。

文法怎麼回事?為什麼不是像我想的那樣?

請出IL。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.