C# Boxing vs UnBoxing

前言:

BoxingUnBoxing在.net中,我們可能在無意識使用到但這個事情確會造成一些效能影響…

.NET兩種類型

在.NET有分兩種類型

  1. 值類型(int,double,char….)
  2. 參考類型(自行宣告的類別,string….)

而存放資料的方式也有兩種:

  1. 堆疊Stack
  2. 堆積Heap

談談Boxing和UnBoxing之前,我們先來了解StackHeap

值類型(Value Type)會存取在Stack記憶體區塊中

參考類型(Reference Type)內容會在Heap記憶體區塊上,Stack會指向Heap上記憶體位置(有點像c++傳址)

如下圖

了解StackHeap

我們來談談BoxingUnBoxing

Boxing:

型態由大轉小

1
2
int i=20;
object o=(object)i;
int強制轉型為object 因為我們所有物件都是繼承於object物件

原本值類型存在Stack中,但因為我們強轉成Object = 20會存在Heap記憶體區塊中.

因為Object是ReferType型別,這個現象就是Boxing

如下圖

UnBoxing:

型態由小轉大(小轉大會有轉型出錯的問題)

1
2
3
int i=20;
object o=(object)i;
int j=(int)o;

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
2
DataTable dt= new DataTable();
dt.Rows[0]["col1"] //返回一個object型態的物件

所以我在讀取DB資料時建議使用DataReader而不是使用DataTable,因為使用DataReader可以直接去得使用型態(避免Boxing and 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 許可協議。轉載請註明出處!


如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^