C#中的string是System.String的別名,繼承與System.Object。我們可以通過下面的代碼查看類型的繼承關系。
轉到定義可以看到是個class類型,是字符char的集合。string既然是引用類型,為什么不能直接通過參數傳遞在函數中修改呢?
這是因為string類型的不可變性,存儲的字符串數值(這里指的是具體的內容常量,而不是對象)是不變的,string對象每次賦值不同的字符串時,都會創建一個新的對象。
我們看一下下面的例子:
可以看到第一次賦值str1和str2引用相同,但是第二次賦值之后引用不同。
在字符串直接賦值時,會把字符串的數值存放在一個緩存池中,當有其他的變量賦予相同的字符串時,是直接引用緩存池中的數值,這樣就可以節省存儲空間,不需要為每個變量分配相同的字符串空間。
例如上述代碼中str1賦值“ab”時,“ab"就存放在緩存池中。當str2得到計算結果時,會從緩存池中查找,發現有相同的字符串,直接賦予引用,所以str1和str2的引用相同,就是True。
第二個為什么變為False了呢?
因為帶有變量的操作不會存入緩存池,只有直接常量字符串操作會存在緩存池中。可以用過string.IsInterned查詢字符串是否在緩存池中。
static void Main(string[] args) { string str1 = "ab"; string str2 = "a" + "b"; Console.WriteLine("str1={0} (str1==str2)={1} ReferenceEqual={2} IsInterned={3}", str1, str1==str2, object.ReferenceEquals(str1, str2), string.IsInterned(str1)); str1 += "c"; str2 += "c"; Console.WriteLine("str1={0} (str1==str2)={1} ReferenceEqual={2} IsInterned={3}", str1, str1==str2, object.ReferenceEquals(str1, str2), string.IsInterned(str1)); }
可以看出重新賦值后即使str1和str2相等(保存的字符串內容相等),但是引用不相同,“abc”字符串也不在緩存池中。
string常用函數
Compare | 對比兩個字符串 |
Equals | 判斷兩個字符串內容是否相等 |
Format | 字符串格式化 |
IndexOf | 查找第一個匹配到的字符或字符串下標 |
LastIndexOf | 查找最后一個匹配到的字符或字符串下標 |
IsNullOrEmpty | 判斷字符串是否為null或"" |
Remove | 刪除字符串 |
Replace | 替換字符串 |
Split | 分割字符串 |
Substring | 根據位置獲取子串 |
ToCharArray | 字符串轉char數組 |
ToLower | 字符串轉小寫 |
ToUpper | 字符串轉大寫 |
Trim | 刪除頭尾空格 |
字符串賦值時如果希望保留轉義字符可以使用@符號,例如:
string text = @"This is my blog. \n\t\r ""welcome everybody"""; Console.WriteLine(text);
輸出:
This is my blog.
\n\t\r
"welcome everybody"
可以使用$符號進行內插,方便字符串格式化,例如:
string owner = "my"; string text = $"This is {owner} blog. 1+1={1 + 1} Time:{DateTime.Now}"; Console.WriteLine(text);
輸出:This is my blog. 1+1=2 Time:2022/4/21 1:08:38
如果頻繁的操作字符串,可以考慮使用StringBuilder進行優化。
StringBuilder sb = new StringBuilder("StringBuilder."); sb.Append("Append text."); Console.WriteLine("length={0} capacity={1} string={2}",sb.Length, sb.Capacity, sb.ToString()); sb.Insert("StringBuilder.".Length, "Insert text."); Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString()); sb.Replace("Append text.", "Replace text."); Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString()); sb = sb.Remove(0, "StringBuilder.".Length); Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString()); sb.Length = 6; Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString());
輸出