前言:
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.Format
DataTable
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效能問題了.
Box_UnBoxing Sample Code
小結
希望本篇文章可以讓大家對於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 許可協議。轉載請註明出處!