您的位置:首页 > 编程语言 > C#

C#中string的一些特性

2010-03-14 11:38 183 查看
  C#中string类型是一个比较特别的类型,它是一种引用类型,但在使用中,它表现的像一个值类型一样。这是因为string是不可变的(immutable)。

  string具有以下的一些特性:

  1. string是一个字符序列,是String类的一个别名,别且它是一个关键字。

  2. string是引用类型,每个string实例是一个常量,是不可变的,因此对一个string进行修改时,实际上都是创建了一个新实例。    

代码 1 static void Main(string[] args)
2 {
3 string str = "First";
4 Console.WriteLine(string.IsInterned(str) != null);//结果是True
5
6 string str_1 = "First";//str_1的值与str相同
7 Console.WriteLine(string.IsInterned(str_1) != null);//结果是True
8
9 Console.WriteLine(string.ReferenceEquals(str, str_1));//结果是True,str和str_1指向同一个实例
}   4. 编译器会对字符串的操作进行优化。

static void Main(string[] args)
{
string str = "First" + "Second";//看上去是创建了两个字符串实例
Console.WriteLine(str);
}   看上去,好像是先创建了两个字符串实例,实际上编译器已经对这种能明确结果的运算进行了优化,在MSIL中:

1 .method private hidebysig static void Main(string[] args) cil managed
2 {
3 .entrypoint
4 // 代码大小 15 (0xf)
5 .maxstack 1
6 .locals init ([0] string str)
7 IL_0000: nop
8 IL_0001: ldstr "FirstSecond"
9 IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call void [mscorlib]System.Console::WriteLine(string)
IL_000d: nop
IL_000e: ret
} // end of method Program::Main  在文章中还有对其他情况进行更详细的实验。

  [b]另外[/b],我们会经常判断一个字符串是否为空,使用str.Length == 0速度最快,这点网上有很多比较了,自己证明一下也很容易。使用Reflector查看了string.IsNullOrEmpty()的具体实现后,也的确是用这样的判断方法。

1 public static bool IsNullOrEmpty(string value)
2 {
3 if (value != null)
4 {
5 return (value.Length == 0);
6 }
7 return true;
8 }

  还有,是关于string.Empty与“”的区别,通过Reflector,能够看到string.Empty是这样定义和初始化的:

1 public static readonly string Empty;
2
3 static String()
4 {
5 Empty = "";
6 WhitespaceChars = new char[] {
7 '\t', '\n', '\v', '\f', '\r', ' ', '\x0085', '\x00a0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
8 ' ', ' ', ' ', ' ', '​', '\u2028', '\u2029', ' ', ''
9 };
}  那么我们这样使用

static void Main(string[] args)
{
string str = string.Empty;
string str_1 = "";
Console.WriteLine(string.IsInterned(str) != null);//结果是True
Console.WriteLine(string.IsInterned(str_1) != null);//结果是True
Console.WriteLine(string.ReferenceEquals(str,str_1));//结果是True
}  str和str_1的指向是同一个实例。这说明了string.Empty与""其实是一样的,有点小区别的,就是使用string.Empty的性能要比""稍微好点,因为使用string.Empty则会直接指向这个静态变量值,而直接使用""会有一次搜索拘留池的操作。

  最后,来个比较全的例子对string的拘留池以及在内存中创建的string实例进行总结下:

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace ConsoleApplication1
7 {
8 class Program
9 {
static void Main(string[] args)
{
string a = new StringBuilder().Append('a').ToString();
string b = new StringBuilder().Append('b').ToString();
string c = new StringBuilder().Append('c').ToString();
string d = new StringBuilder().Append('d').ToString();
string e = new StringBuilder().Append('a').Append('b').ToString();
string f = new StringBuilder().Append('e').Append('f').ToString();
string g = new StringBuilder().Append('m').Append('n').ToString();
string h = new StringBuilder().Append('e').ToString();
string m = new StringBuilder().Append('m').ToString();
string n = new StringBuilder().Append('n').ToString();

Console.WriteLine(string.IsInterned(a) != null);//结果为False,拘留池中没有储存"a"
Console.WriteLine(string.IsInterned(b) != null);//结果为True,因为本函数中(下面b1变量)已经有明文字符串"b",则会被添加到拘留池
Console.WriteLine(string.IsInterned(c) != null);//结果为False,拘留池中还没有储存"c",注意调用Test()后的结果
Console.WriteLine(string.IsInterned(d) != null);//结果为False,拘留池中还没有储存"d",注意实例化TestClass后的结果
Console.WriteLine(string.IsInterned(e) != null);//结果为False,拘留池中没有储存"ab"
Console.WriteLine(string.IsInterned(f) != null);//结果为True,下面f1变量中的"e"+"f"会被优化成"ef",将"ef"添加到拘留池
Console.WriteLine(string.IsInterned(g) != null);//结果为False,拘留池中没有储存"mn"
Console.WriteLine(string.IsInterned(h) != null);//结果为False,下面f1变量中的"e"+"f"会被优化成"ef",不会有"e"被添加到拘留池
Console.WriteLine(string.IsInterned(m) != null);//结果为True,给g1变量初始化时,将"m"添加到拘留池
Console.WriteLine(string.IsInterned(n) != null);//结果为True,给g1变量初始化时,将"n"添加到拘留池

Test();
Console.WriteLine(string.IsInterned(c) != null);//结果为True,调用的Test()方法中,已经将"c"添加拘留池中
TestClass testClass = new TestClass();
Console.WriteLine(string.IsInterned(d) != null);//结果为True,实例化TestClass时,已经将"d"添加拘留池中

string b1 = "b";//CLR会将当前的方法中所有出现的的明文字符串(优化后的如"x"+"y"则被优化为"xy")添加到拘留池,然后才开始运行,故变量b1虽然定义在后面,但"b"已经被添加到拘留池了
string f1 = "e" + "f" + a;//编译器会优化为"ef"+a,并将"ef"添加到拘留池,不会将"e"和"f"添加到拘留池
string g1 = "m" + a + "n";//将"m"和"n"添加到拘留池
string f2 = "efa";//将"efa"添加到拘留池
string f3 = "e" + "f" + "a";//编译器会优化为"efa",f3将指向拘留池的内存

//上述string.IsInterned()方法只是查看变量的值是否在添加到拘留池中,并不表示变量指向拘留池的内存
//事实上非明文字符串的变量都将指向开辟新内存

Console.WriteLine(string.ReferenceEquals(b1, b));//结果为False,变量b的值"b"在拘留池中已经存在,但b指向的是新开辟内存,b1指向的是拘留池的内存
Console.WriteLine(string.ReferenceEquals(b1, "b"));//结果为True

Console.WriteLine(string.ReferenceEquals(f1, f2));//结果为False,f1指向的是"ef"+a运算时新开辟的内存,f2指向的是拘留池的内存
Console.WriteLine(string.ReferenceEquals(f2, f3));//结果为True,f3被编译器优化为"efa",因此也指向拘留池的内存
Console.WriteLine(string.ReferenceEquals(f3, "efa"));//结果为True
}

static void Test()
{
string c1 = "c";
}
}
public class TestClass
{
string d1 = "d";
}
}

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: