String與StringBuilder 辯議

文中對String和StringBuilder的用法有一些偏差,首先,str = str.SubString(0, str.Length - 1)和str = str.SubString(1)的效率應該相差不大,String.SubString(int)的實現如下:

public string Substring(int startIndex)
{
      
return this.Substring(startIndex, this.Length - startIndex);
}

  因爲SubString的兩個重載如果需要得到相同長度的子串,分配內存和拷貝數據的時間消耗應當是差不多的。

  StringBuilder的ToString方法提供了一個重載,如下:
public string ToString(int startIndex, int length)
{
      
return this.m_StringValue.Substring(startIndex, length);
}

  m_StringValue是一個string的實例,用以維持StringBuilder內部的值。因爲SubString只涉及到內存分配和拷貝,而設置StringBuilder的Length時,需要更新StringBuilder的狀態,並且最終使用時仍需要一次ToString()操作,在set_Length和ToString()時都可能會產生新的string實例,因此兩種用法效率上的差別是無法直觀判斷的,需要通過測試來確定。現在的項目中我使用的是設置Length的方式,但有意圖要測試一下ToString()的情況,以確定是否需要修改。

  StringBuilder是一個expensive的對象,構建時代價比較大,因此除非有大量的或是無法預知次數的字符串操作,否則可以用string的操作來代替。原文中的幾個功能都可以用string類的方法來實現。

  首先是實現包含n個空格的字符串,有如下兩種方式,效率都比較高:
string str1 = String.Empty.PadRight(10);
string str2 = new String(' '10);

  除了空格外,PadRight也可以指定其他的填充字符。

  要生成類似於"a,b,c,d,e,f"這樣的字符串,可以用String類的靜態方法String.Join,代碼如下:
string str = String.Join(","new string[]{"a""b""c""d""e"});

  StringBuilder可以用來進行大量的字符串操作,但是構建StringBuilder的代碼比較大,因此對於簡單的字符串連接操作,可以使用String.Concat(params string[])方法。實際上,C#的編譯器會爲字符串的operator +生成調用String.Concat(params string[])的中間代碼。編譯器也爲多個字符串的連接做了優化,例如以下四個字符串相連接,僅生成一次String.Concat(params string[])調用,而不是三次字符串連接。


string str1 = "hello";
string str2 = "world";

string str = str1 + " " + str2 + "!";


  String.Concat會分析傳入的多個參數,一次性分配結果所需的內存,並將參數值依次拷貝到結果字符串的相應部分,效率還是相當高的。

  那麼,以下的代碼會生成對哪個方法的調用呢?

string str1 = "hello";
string str2 = "world";
int i = 2;

string str = str1 + " " + i + str2 + "!";

  因爲i是Int32,因此根據Overload的規則,編譯器最終會產生對String.Concat(params object[])的調用,這個方法的執行過程與String.Concat(params string[])類似,但會爲每一個參數調用ToString()操作,即便此參數是string類的實例,因此,爲了減少這一開銷,應當如下編寫:

string str1 = "hello";
string str2 = "world";
int i = 2;

string str = str1 + " " + i.ToString() + str2 + "!";

  最後,要說明的是string.PadRight及string.Join,還有string的構造函數,其最終依賴的實現方法聲明都類似於:
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern string Join(string separator, string[] value, int startIndex, int count);
  
  這類代碼都是內部實現的,效率非常高。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章