二十六:使用String类型(一)
String类型是一个引用类型,直接派生自Object,因此String对象总是存在于堆上,而不是线程堆栈上。
许多编程语言(包括C#)都将String视为一个基元类型,也就是说编译器允许在源代码中直接表示直接量字符串,编译器将这些直接量字符串放到模块的元数据中,并在运行时加载并引用它们。
在C#中不能通过new关键字操作符在一个直接量字符串的基础上构造一个String对象:
using System;
public sealed class Program
{
public static void Main()
{
String s = new String("hellow world"); //编译不通过
Console.WriteLine(s);
}
}
必须使用以下简化的写法:
using System;
public sealed class Program
{
public static void Main()
{
String s = "hellow world";
Console.WriteLine(s);
}
}
编译上面代码,查看其IL代码如下:
{
.entrypoint
// 代码大小 15 (0xf)
.maxstack 1
.locals init ([0] string s)
IL_0000: nop
IL_0001: ldstr "hellow world"
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
IL指令newobj用于构造一个对象的新实例,然而在上面的IL代码中并没有发现newobj指令,只有一个特殊的IL指令ldstr(load string),它使用从元数据获取的一个直接量字符串来构造一个String对象。
如果使用不安全代码,那么可以在一个Char*或者Sbyte*的基础上构造一个String对象,因此,可以使用new的操作符,并调用String提供的、能接受Char*或Sbyte*参数的某个构造器,这些构造器将创建一个String对象,根据一个由Char实例或者signed字节构成的数组来初始化字符串。
可以使用C#的+操作符将几个字符串连接成一个,如下:
//三个直接量字符串连接成一个直接量字符串
String s = "hellow" + " " + "world";
上面代码中,由于所有字符串都是直接量,所以C#编译器会在编译时连接它们,最统终会将一个字符串(hellow word)放到模块的元数据中。如果对非直接量字符串使用+操作符,那么连接会在运行时进行,它会在垃圾收集堆上创建多个字符串对象,此种情况应该使用StringBuilder类型。
C#提供了@字符来声明字符串方法,采用这种方法叫做“逐字字符串”,引号之间的所有字符都会被字符串的一部分,通常用于表示文件目录或者正则表达式,如下,写法不一样,但是它们在程序集的元数据中生成完全一致的字符串:
// \当作转义字符
String s = "C:\\WINDOWS\\system32\\notepad.exe";
// \当作字符串的一部分
String s = @"C:\WINDOWS\system32\notepad.exe";