C# 指南之裝箱與拆箱

來源:互聯網
上載者:User
知識點 
  1. 實值型別。

    1. 實值型別是在棧中分配記憶體,在聲明時初始化才能使用,不能為null。
    2. 實值型別超出作用範圍系統自動釋放記憶體。
    3. 主要由兩類組成:結構,枚舉(enum),結構分為以下幾類:
      1. 整型(Sbyte、Byte、Char、Short、Ushort、Int、Uint、Long、Ulong)
      2. 浮點型(Float、Double)
      3. decimal
      4. bool
      5. 使用者定義的結構(struct)
  2. 參考型別。
    1. 參考型別在堆中分配記憶體,初始化時預設為null。
    2. 參考型別是通過記憶體回收機制進行回收。
    3. 包括類、介面、委託、數組以及內建參考型別object與string。
概念

由於C#中所有的資料類型都是由基類System.Object繼承而來的,所以實值型別和參考型別的值可以通過顯式(或隱式)操作相互轉換,而這轉換過程也就是裝箱(boxing)和拆箱(unboxing)過程。

  1. 裝箱 是實值型別到 object 類型或到此實值型別所實現的任何介面類型的隱式轉換。對實值型別裝箱會在堆中分配一個對象執行個體,並將該值複製到新的對象中。 

    •  
  2. 拆箱(unboxing)是從 object 類型到實值型別或從介面類型到實現該介面的實值型別的顯式轉換。unboxing操作包括:
    1. 檢查對象執行個體,確保它是給定實值型別的一個裝箱值。(拆箱後沒有轉成原類型,編譯時間不會出錯,但運行會出錯,所以一定要確保這一點。用GetType().ToString()判斷時一定要使用類型全稱,如:System.String 而不要用String。)

    2. 將該值從執行個體複製到實值型別變數中。

樣本

首先寫個簡單的控制台程式:

// Tutorial_boxing_unboxing.cs
// 裝箱與拆箱
using System;

class App
{
    static void Main()
    {
        int i = 32;
        object o = i; //隱式裝箱

         Console.WriteLine("o = {0}", o);

        Console.Read();
    }
}

其中object o = i這裡我們進行了裝箱操作,然後我們用MSIL 反組譯工具查看下產生的.exe程式的內部機理。

 1 .method private hidebysig static void  Main() cil managed
 2 {
 3   .entrypoint
 4   // 代碼大小       30 (0x1e)
 5   .maxstack  2
 6   .locals init ([0] int32 i,
 7            [1] object o)
 8   IL_0000:  nop
 9   IL_0001:  ldc.i4.s   32
10   IL_0003:  stloc.0
11   IL_0004:  ldloc.0
12   IL_0005:  box        [mscorlib]System.Int32
13   IL_000a:  stloc.1
14   IL_000b:  ldstr      "o = {0}"
15   IL_0010:  ldloc.1
16   IL_0011:  call       void [mscorlib]System.Console::WriteLine(string,
17                                                                 object)
18   IL_0016:  nop
19   IL_0017:  call       int32 [mscorlib]System.Console::Read()
20   IL_001c:  pop
21   IL_001d:  ret
22 } // end of method App::Main

其中第12行是我們的裝箱操作。(關於IL中出現的操作符代表的操作請查閱MSDN Library中的.NET開發/.NET Framework SDK/類庫參考/System.Reflection.Emit/OpCodes 類/OpCodes 欄位)

然後我們unboxing操作:

    static void Main()
    {
        int i = 32;

        Console.WriteLine("i = {0}", i);

        Console.Read();
    }

再用MSIL工具查看產生的.exe,如下結果:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // 代碼大小       28 (0x1c)
  .maxstack  2
  .locals init ([0] int32 i)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   32
  IL_0003:  stloc.0
  IL_0004:  ldstr      "i = {0}"
  IL_0009:  ldloc.0
  IL_000a:  box        [mscorlib]System.Int32
  IL_000f:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
  IL_0014:  nop
  IL_0015:  call       int32 [mscorlib]System.Console::Read()
  IL_001a:  pop
  IL_001b:  ret
} // end of method App::Main

在IL_000a行,我們發現這裡卻也出現了一個box!不過這步是在call System.Console::WriteLine(string, object)時發生的。我們對比前面我們手動boxing的IL代碼,發現在我們手動boxing後就沒有這步box了。為什麼呢?

當我們在調用一些方法的重載版本時,由於編譯器找不到符合給定參數類型的重載方法,此時編譯器便去尋找到的最接近的版本,然後使用找到的方法,而其參數卻是我們傳入的實值型別的基類如System.Object或者其實現的介面類型,接著編譯器為了求得與這個方法的原型一致,就必須對該實值型別進行裝箱操作(轉換成參考型別)。

照這個說法當我們不手動boxing時,在調用了Console.WriteLine()方法輸出一個Int32類型值時,系統就要自動進行boxing。也就是說如果我們要對該輸出操作作5000次的迴圈,系統就要做5000次的boxing。這樣對效能便會有一定的影響,而且要使迴圈次數是100,000,000次呢,或者跟多!

此時我們便要想如何消除這不應該的效能損失!正如第一個程式是展示的,我們可以在需要的地方先進行boxing,這個原理很簡單,我們可以聯想到類似的做法:

//當我們如下時:
for (int i = 0; i < arr.Length; i++)
{
   // 
}

//我們更因該這樣:
int L = arr.Length;
for (int i = 0; i < L; i++)
{
   // 
}

這樣,我們只要一次boxing,就可以避免讓系統重複的做這個操作。

用途

像在調用Console.WriteLine()的過程中系統自動進行boxing一樣,當我們在調用其它的一些方法的重載版本進行操所時,為了避免由於無謂的隱式裝箱所造成的效能損失,在執行這些多類型重載方法之前,最好先對值進行裝箱。一般是在處理大量資料需要對類型進行裝箱操作。

 

本篇內容參考自MSDN文檔。

本Blog中所有內容皆以“現狀”提供且沒有任何擔保,同時也沒有授予任何權利。
This posting is provided "AS IS" with no warranties, and confers no rights.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.