建議1 正確操作字串

2021-07-22 03:24:52 字數 3745 閱讀 5143

建議1: 正確操作字串

字串應該是所有程式語言中使用最頻繁的一種基礎資料型別。如果使用不慎,我們就會為一次字串的操作所帶來的額外效能開銷而付出代價。本條建議將從兩個方面來**如何規避這類效能開銷:

先來介紹第乙個方面,請看下面的兩行**:

string str1 = "

str1

"+ 9

; string str2 = "

str2

"+ 9.tostring();

為了清楚這兩行**的執**況,我們來比較兩者生成的il**。

第一行**對應的il**如下:

.maxstack  8

il_0000: ldstr

"str1

"il_0005: ldc.i4.s

9il_0007: box [mscorlib]system.int32

il_000c: call

string [mscorlib]system.string::concat(object, object

) il_0011: pop

il_0012: ret

第二行**對應的il**如下:

.maxstack  2

.locals init ([

0] int32 cs$0$0000

) il_0000: ldstr

"str2

"il_0005: ldc.i4.s

9il_0007: stloc.

0il_0008: ldloca.s cs$

0$0000

il_000a: call instance

string

[mscorlib]system.int32::tostring()

il_000f: call

string [mscorlib]system.string::concat(string, string

) il_0014: pop

il_0015: ret

可以看出,第一行**「str1」+ 9在執行時會完成一次裝箱行為(il**中的box);而第二行**中的9.tostring()並沒有發生裝箱行為,它實際呼叫的是整型的tostring方法。tostring方法的原型為:

public

override

string tostring()

可能有人會問,是不是原型中的number.formatint32方法會發生裝箱行為呢?實際上,number.formatint32方法是乙個非託管的方法,其原型如下:

[methodimpl(methodimploptions.internalcall), securitycritical]  

public

static

extern

string formatint32(int value, string format, numberformatinfo info);

它是通過直接操作記憶體來完成從int到string的轉換,效率要比裝箱高很多。所以,在使用其他值引用型別到字串的轉換並完成拼接時,應當避免使用操作符「+」來完成,而應該使用值引用型別提供的tostring方法。

也許有人還會提出疑問:上文所舉的示例中,即使fcl提供的方法沒有發生裝箱行為,但在其他情況下,fcl方法內部會不會含有裝箱的行為呢?答案是:也許會存在。不過,我們這裡有乙個指導原則:

在自己編寫的**中,應當盡可能地避免編寫不必要的裝箱**。

注意 裝箱之所以會帶來效能損耗,因為它需要完成下面三個步驟:

1)首先,會為值型別在託管堆中分配記憶體。除了值型別本身所分配的記憶體外,記憶體總量還要加上型別物件指標和同步塊索引所占用的記憶體。

2)將值型別的值複製到新分配的堆記憶體中。

3)返回已經成為引用型別的物件的位址。

第二個方面:避免分配額外的記憶體空間。對clr來說,string物件(字串物件)是個很特殊的物件,它一旦被賦值就不可改變。在執行時呼叫 system.string 類中的任何方法或進行任何運算(如「=」賦值、「+」拼接等),都會在記憶體中建立乙個新的字串物件,這也意味著要為該新物件分配新的記憶體空間。像下面的 **就會帶來執行時的額外開銷。

private

static

void

newmethod1()

private

static

void

newmethod6()

而在以下**中,字串不會在執行時拼接字串,而是會在編譯時直接生成乙個字串。

private

static

void

newmethod2()

private

static

void

newmethod9()

由於使用 system.string 類會在某些場合帶來明顯的效能損耗,所以微軟另外提供了乙個型別stringbuilder來彌補string的不足。

stringbuilder並不會重新建立乙個string 物件,它的效率源於預先以非託管的方式分配記憶體。如果stringbuilder 沒有先定義長度,則預設分配的長度為16。當 stringbuilder 字元長度小於等於 16時,stringbuilder 不會重新分配記憶體;當 stringbuilder 字元長度大於16 小於 32時,stringbuilder 又會重新分配記憶體,使之成為 16的倍數。在上面的**中,如果預先判斷字串的長度將大於16,則可以為其設定乙個更加合適的長度(如32)。stringbuilder重新分配內 存時是按照上次的容量加倍進行分配的。當然,我們需要注意,stringbuilder指定的長度要合適,太小了,需要頻繁分配記憶體;太大了,浪費空間。

曾經有人問我,下面的兩種字串拼接方式,哪種效率更高:

1.      private

static

void

newmethod8()

2. private

static

void

newmethod7()

答案是:兩者效率都不高。不要以為前者比後者建立的字串物件更少,事實上,兩者建立的字串物件相等,且前者進行了3次string.contact方法呼叫,比後者還多了兩次。

要完成這樣的執行時字串拼接(注意:是執行時),更佳的做法是使用stringbuilder型別,**如下所示:

private

static

void

newmethod10()

微軟還提供了另外乙個方法來簡化這種操作,即使用string.format方法。string.format方法在內部使用stringbuilder進行字串的格式化,如下面的**所示:

private

static

void

newmethod11()

", a, b, c, d);

}

**:《編寫高質量**改善c#程式的157個建議》陸敏技

建議1 正確操作字串

字串是我們常用的基礎資料型別,如果使用不當,養成不好的習慣,會對程式造成額外的開銷。建議 確保盡量少的裝箱 避免分配額外的記憶體空間 確保盡量少的裝箱 1 string str1 str1 9 2 string str2 str2 9.tostring 第一行 需要執行一次裝箱行為int 轉 obj...

字串操作 1

a 大串中查詢子串出現的次數 public class substringdemo 方式2 不擷取字串,逐漸縮小查詢範圍 private static intgetcount2 string str,string regex return count 方式1 查詢到小串後將已經查詢的部分擷取掉。返回...

C 中如何正確的操作字串?

字串應該是所有程式語言中使用最頻繁的一種基礎資料型別。如果使用不慎,我們就會為一次字串的操作所帶來的額外效能開銷而付出代價。本條建議將從兩個方面來 如何規避這類效能開銷 1.確保盡量少的裝箱 2.避免分配額外的記憶體空間。第乙個方面 確保盡量少的裝箱 對於裝拆箱,我們應該不陌生,值型別轉換成引用型別...