C#锐利体验 第十二讲 字符串

来源:互联网 发布:小学生学计算机编程 编辑:程序博客网 时间:2024/04/28 09:06

第十二讲 字符串

字符串
???????字符串在C#中是System.String(或简化作小写string)类的一个实例,它表示一个不变的字符序列。字符串的创建的语法很简单:string s = "C# Sharp XP";即在托管堆上创建了内容为字符串"C# Sharp XP"的内存区域,而s仅仅是指向该内存区域的一个引用句柄。看下面的代码行:
string s1="Hello,World!";
string s2=s1;
???????这时,s1和s2都指向同一块含"Hello,World!"的内存区。
C#为字符串提供了两种转义表达。第一种和传统C/C++中的转义字符表达相同,即用反斜线”/”加特定字符的表达方式。如”/t”表示Tab键,”/r”表示回车,”/n”表示换行等等。我们要表示C盘“我的文档”下的一个文件路径,string MyPath=”C://Documents and Settings//Cornfield//My Documents//MyFile.cs”,其中双斜线被转义为单斜线。而采用第二种表示方法,我们可以在字符串前加一个“@”符号即可按正常的字符序列来表达字符串,如上面的文件路径可以象这样来表达:string MyPath=@”C:/Documents and Settings/Cornfield/My Documents/MyFile.cs”,和前面的表达效果相同。第二种表示方法在我们表达包含特殊字符的长字符串的情况下非常有用,它甚至能够表达不能够显示为字符形式的回车,换行等特殊字符。
可以通过索引器来获取字符串中的单个字符(16位Unicode编码)——这和C/C++中的字符串数组在本质上是完全不同的。下面的代码演示了这一点:
string s = "C# Sharp XP";
for (int index = 0; index < s.Length; index++)
????Console.WriteLine(s[index]);
???????由于字符串恒定性的缘故,我们不能做类似s[index]=’p’的改变,这是由System.String的只读索引器public char this[int index] {get;}来保证的。
???????作为System.String类型的实例,系统为字符串提供了丰富多样的操作,这里只对几个比较特殊的方法做一剖析。String类实现了ICloneable接口,但String.Clone方法并不是返回一个新创建的String实例,而是仅仅返回一个和参数一样的引用句柄,也就是说string s2=s1.Clone()和前面的string s2=s1效果一样。需要返回一个和参数内容一样,但引用句柄不同的字符串可以采用静态的String.Copy方法。实例方法System.Equal,和类操作符public static bool operator ==(string a,string b);比较的都是两个字符串的内容是否相等,而非引用句柄。下面的代码示例,集中展示了上述方法的行为:
using System;
class Test
{
????public static void Main()
????{
????????string s1 = "Hello,World!";
????????string s2= s1.Clone().ToString();//克隆,句柄相等,内容相等
????????string s3 = string.Copy(s1); // 拷贝,句柄不等,内容相等
????????
????????Console.WriteLine(s1==s2);//True,内容相等
??????Console.WriteLine(s1==s3);//True,内容相等
????????
????????Console.WriteLine((object)s1==(object)s2);//True,句柄引用相等
????????Console.WriteLine((object)s1==(object)s3);//False,句柄引用不等
????}
}


字符串恒定性
字符串的恒定的意思是指一旦字符串的值(System.String实例)被创建后,它便不可以改变.我们看下面一个典型的代码行:
string s1="Hello,";
string s2="World!";
s1+=s2;
???????上面的语句执行完后,s1=”Hello,World!”,s2=”World!”。但s1原来的值”Hello,”并没有因此消失,确切地讲”Hello,”仍然占有内存空间,只不过现在不能被我们引用到而已,它只能等待.NET的自动垃圾收集器来回收其资源,这在以前的C++中就造成了内存泄漏.也就是说在上面的语句执行后,我们将拥有”Hello,World!”(s1引用句柄的指向的值),”World!”(s2引用句柄指向的值),”Hello,”(没有引用句柄指向该值)共三个存储字符串的内存区.
???????字符串值恒定的特征还表现在作为string类型的参数传递上,我们看下面的例子:
using System;
class Test
{
????public static void Main()
????{
????????string p="Hello,";
?????????MyMethod(p);
????????Console.WriteLine(p);//输出Hello,
????}
????public static void MyMethod(string p)
????{
????????p+="World!";
????????Console.WriteLine(p);//输出Hello,World!
????}
}
???????虽然我们说string类型在C#中是一种引用类型,但由于字符串的恒定的性质,我们的方法MyMethod并没有改变传进来的p的引用句柄(若要改变则需要采用ref关键字修饰参数),而这个引用句柄本身指向的表达字符串"Hello,"的内存区域也没有改变,自然通过MyMethod方法的调用字符串p也就不会改变。
理解字符串值恒定的特征对我们在C#中熟练操作字符串非常重要,比如System.String类的很多的方法实际上并没有改变参与操作的字符串本身,而是创建一个新值,仅仅把原来的字符串丢给自动垃圾收集器。如果C#程序中频繁地操作字符串,很有可能引起字符串大量的“创建/丢弃”动作,势必给系统造成负担,这时我们应该借助于StringBuilder类。StringBuilder位于System.Text命名空间下,它的实例不是字符串,但它为可变字符串提供了丰富的操作——插入,追加,替换,删除等,同时由于它的操作发生在同一块内存区,因此没有恒定字符串System.String频繁的“创建/丢弃”的消耗。可以非常方便地利用构造器public StringBuilder(string value);来创建含有value字符串值的StringBuilder类实例,同样可以用StringBuilder的实例方法ToString非常方便地得到类型为string的他的字符串内容。和System.String类的很多方法相反,StringBuilder类的很多方法改变的正是参与操作的StringBuilder类实例本身,并不创建新值!
作为一个一般性的原则,我们如果仅仅涉及到字符串的内容表示,或者创建新的字符串,我们往往采用System.String的方法就可以了。但如果要涉及到大量的字符串内容的变更操作时,就很有必要采用StringBuilder类的一些相关方法,然后再调用ToString方法得到我们需要的字符串。

原创粉丝点击