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());
输出