前言:
Boxing跟UnBoxing在.net中,我們可能在無意識使用到但這個事情確會造成一些效能影響…
.NET兩種類型
在.NET有分兩種類型
- 值類型(int,double,char….)
- 參考類型(自行宣告的類別,string….)
而存放資料的方式也有兩種:
- 堆疊Stack
- 堆積Heap
談談Boxing和UnBoxing之前,我們先來了解Stack和Heap
值類型(Value Type)會存取在Stack記憶體區塊中
參考類型(Reference Type)內容會在Heap記憶體區塊上,Stack會指向Heap上記憶體位置(有點像c++傳址)
如下圖

了解Stack和Heap後
我們來談談Boxing和UnBoxing
Boxing:
型態由大轉小
1 | int i=20; |
原本值類型存在Stack中,但因為我們強轉成Object = 20會存在Heap記憶體區塊中.
因為Object是ReferType型別,這個現象就是
Boxing
如下圖

UnBoxing:
型態由小轉大(小轉大會有轉型出錯的問題)
1 | int i=20; |
將Object強轉成int在這個案例不會有問題,但如果是將o轉為char就會有問題
在執行UnBoxing如下圖
可以看到原本存在Heap上值 我們會把他搬回Stack並附值給J

把
Heap上直搬回Stake上就會遇到UnBoxing.
.Net現實生活中常遇到的案例
String.FormatDataTable
String.Format的Boxing
1 | public static string Format(string format, params object[] args) |
我們常使用上面String.Format重載方法,但使用這個方法會不小心遇到Boxing問題
我們在呼叫方法時假如參數是一個Value Type,.Net會在呼叫前把此值複製在傳入方法中(如果是Refer Type傳入此物件Heap記憶體位置).
String.Format吃參數是Object,所以如果傳入參數是Value Type如(1,1.1m)就會遇到Boxing.
但如果我們在呼叫
String.Format前使用ToString方法就可以避免Boxing的動作,$"{times.ToString()}".
DataTable的Boxing UnBoxing
我們在ADO.Net將資料存放在DataTable就會經歷一次Boxing在利用DataTable.Row[][]返回是一個Object型態資料(因為會把ValueType型別資料放進Heap中).
我們在取用時會把Object轉成我們希望型態(UnBoxing).
1 | DataTable dt= new DataTable(); |
所以我在讀取DB資料時建議使用
DataReader而不是使用DataTable,因為使用DataReader可以直接去得使用型態(避免Boxing and UnBoxing).
常使用誤區string.format Boxing UnBoxing
在開始說明之前先問問大家兩個問題
下面兩段程式碼是否是一樣?
如果不一樣是哪裡不一樣?
$""是string.format語法糖.
1 | int intVal = 1; |
1 | int intVal = 1; |
上面答案非常明顯是不一樣,但不一樣在哪裡呢?
Boxing和UnBoxing.
要了解String.Format Boxing和UnBoxing之前我們要先了解function是如何傳參數的.
Function如何傳參數
在.net我們常常在寫function但你有注意參數是如何被傳的嗎?
1 | static void Main(string[] args) |
執行結果如下圖

那是因為.net在傳參數時
- 如果方法參數是Ref Type會copy address當作參數進去
- 如果方法參數是Value Type會copy value當作參數進去
我們看String.Format其中一個重載方法,是傳入object[]當作參數.
1 | public static string Format(string format, params object[] args) => args != null ? string.FormatHelper((IFormatProvider) null, format, new ParamsArray(args)) : throw new ArgumentNullException(format == null ? nameof (format) : nameof (args)); |
因為單純傳入value type會導致參數需要boxing(因為方法參數吃object)
所以value type使用ToString方法傳入String.Format方法,先把value type轉成refer type的string就不會造成boxing unboxing效能問題了.
小結
希望本篇文章可以讓大家對於Boxing和UnBoxing更了解,避免踏入這個問題中。
參考連結
參考 MSDN https://msdn.microsoft.com/zh-tw/library/yz2be5wk.aspx
__此文作者__:Daniel Shih(石頭)
__此文地址__: https://isdaniel.github.io/boxing-unboxing/
__版權聲明__:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!