预定义的引用类型.
c#支持两种预定义的引用类型:object 和 string
- object 根类型,其他类型都是从它派生而来的(包括值类型)
- string Unicode字符串
object 类型
许多编程语言和类层次结构都提供了根类型, 层次结构中的其他对象都从它派生而来。c#和 .net 也不例外。
在c#中, object 类型就是最终的父类型, 所有内置类型和用户定义的类型都从它派生而来。
这样 object 类型就可以用于两个目的:
- 可以使用 object 引用来绑定任何特定子类型的对象。 object引用也可以用于反射,此时必须有代码来处理类型未知的对象。
- object 类型实现了许多一般用途的基本方法, 包括 Equals() 、GetHashCode()、GetType() 和 ToString()。 用户定义的类需要使用一种面向对象技术,来提供其中一些方法的替代实现代码。 例如,重写ToString()时, 要给类提供一个方法,给出类本身的字符串表示。如果类中没有提供这些方法的实现代码,编译器就会使用 object 类型中的实现代码,它们在类上下文中执行不一定正确。
string 类型
c#有string关键字, 在遮罩下转换为 .NET类 System.String。 有了它,像字符串连接和字符串复制这样的操作就简单了:
string str1 = "Hello";
string str2 = "World";
string str3 = str1 + str2;
尽管这是一个值类型的赋值, 但 string 是一个引用类型。 string 对象被分配在堆上,而不是栈上。
因此,当把一个字符串变量赋予另一个字符串时,会得到内存中同一个字符串的两个引用。 但是,string与
引用类型的常见行为有一些区别。 例如, 字符串是不可改变的。 修改其中一个字符串, 就会创建一个全新的string对象,
而另一个字符串不发生任何变化。
看看下面的代码
string s1 = "a string";
string s2 = s1;
Console.WriteLine("s1 is " + s1);
Console.WriteLine("s2 is " + s2);
s1 = "another string";
Console.WriteLine("s1 is now " + s1);
Console.WriteLine("s2 is now " + s2);
// 输出结果为
s1 is a string
s2 is a string
s1 is now another string
s2 is now a string
改变s1的值对 s2没有影响, 这与我们期待的引用类型正好相反。 当用值 a string 初始化 s1时, 就在堆上分配了一个新的 string对象。 在初始化 s2时,引用也指向这个对象, 所以 s2的值也是 a string。 但是当s1的值发生改变时,并不会替换原来的值,在堆上会新分配一个对象。 s2变量仍然指向原来的对象, 所以它的值没有改变。 这实际上是运算符重载的结果, 基本上 string类已经实现,其语义遵循一般的、直观的字符串规则。
字符串字面量放在双引号中 ("...") ;如果试图把字符串放在单引号中,编译器就会把它当成 char 类型,从而抛出错误。
C# 字符串和char 一样,可以包含 Unicode 和 十六进制数转义序列。 因为这些转义序列以一个反斜杠开头,所以不能再字符串中使用没有经过转义的反斜杠字符,而需要用两个反斜杠字符 (\\)来表示它:
string filepath = "C:\\ProCSharp\\First.cs";
输入两个反斜杠字符会令人迷惑。 C#提供了替代方式。 可以在字符串字面量的前面加上字符 @ ,在这个字符后的所有字符都看成其原来的含义, 它们不会解释为转义字符:
string filepath = @"C:\ProCSharp\First.cs";