那些年String.Format中的Boxing和UnBoxing

前言:

下面有兩個虛擬程式碼

1
2
3
4
5
int times = 30000000;
string s = string.Empty;

s = $"{times}";
s = $"{times.ToString()}";

請問下面這兩段程式碼有沒有差別?

1
2
s = $"{times}";
s = $"{times.ToString()}";

$""這個程式碼是string.Format()語法糖

如果知道差別的同學,恭喜你已經可以下課了

如果不知道差別也沒關係,讓我細細講述.

String.Format方法簽章

String.Format方法有一個重載方法,可以看到裡面吃參數是params object[]這可以讓我們傳進東西當作參數(他會在方法中呼叫ToString方法).

1
public static string Format(string format, params object[] args)

所以這段程式碼看起來應該是要一樣,但事實並非如此…

1
2
s = $"{times}";
s = $"{times.ToString()}";

$”{times}” vs $”{times.ToString()}”

在執行下面程式碼會發現兩段程式碼不管怎麼執行

執行時間$"{times}";永遠都會比$"{times.ToString()}";來的多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Program
{
static void Main(string[] args)
{
int times = 30000000;
string s = string.Empty;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < times ; i++)
{
s = $"{times}";
}

sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

sw.Restart();
for (int i = 0; i < times ; i++)
{
s = $"{times.ToString()}";
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadKey();
}
}

執行時間如上圖

img

Source Code

這是為什麼呢??

原因出在Boxing和UnBoxing上…

Boxing 和 UnBoxing

在說BoxingUnBoxing之前

我們要了解.Net中的Refer TypeValue Type在記憶體存放上差別.

想了解Refer TypeValue Type的人,可以參考我之前寫文章 【C#】 參考類型 , 值類型 Equals方法 和 ==.

假如已經了解Refer TypeValue Type,在.Net中有分Stack記憶體區段和Heap記憶體區段.

  • Stack:存放Value Type(struct)資料
  • Heap:存放Refer Type資料

Boxing

因為在Boxing時我們會把Value Type資料複製一份資料到Refer Type記憶體中.

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

上面程式碼大概會如下圖操作

int強制轉型為object 因為我們所有物件都是繼承於object物件

UnBoxing

至於UnBoxing動作就如下面程式碼

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

UnBoxing會將原本存在Heap的值,會把他搬回Stack並附值給J

o Object強轉成int在這個案例不會有問題,但如果是將o轉為char就會有問題

(解答)String.Format兩個範例 效能差異

如果有從頭看到尾小夥伴,相信應該可以了解到問什麼會有沒有.ToString會造成差異性了吧.

因為Boxing會造成系統無形中消耗,如果我們先把傳入Value Type資料轉成String再傳入就可以避免Boxing問題.

此文作者:Daniel Shih(石頭)
此文地址https://isdaniel.github.io/stringformat-compare/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!


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