和C++不同,在C#中,bool,char,int,long,double等也是类,一个数字例如24,就是int类型的一个对象,例如:
我们调用了24的ToString方法,从这种我们熟悉的语法现象上可以看出,24是一个对象,它有自己的方法。
一、元类型
.net平台有一种很有意思的机制,叫做数据类型映射机制,即可以将.net Framework定义的一系列类,以不同的名字映射到不同的语言中,所以C#的int类型实际上是一个叫做Int32的类的别名,24是Int32类型的一个对象。
在C#中,只有很少的一部分类的对象可以使用常量来表示(例如24、true、3.14、"hello”),其它类的对象都必须使用new运算符来生成。这类可以用常量来表示的对象成为元类型对象,元类型定义在.net Framework中,System命名空间下。我们来看一下元类型在C#语言中的类型映射。
.net Framework元类型 | C#类型 | 常量值(取值范围) | 字长 |
System.Boolean | bool | true/false | |
System.Byte | byte | 0 - 255 | 无符号8位整数 |
System.Sbyte | sbyte | -128 ~ 127 | 有符号8位整数 |
System.Char | char | 0 ~ 65,535 | 无符号16位整数 |
System.Int16 | short | -32,768 ~ 32,767 | 有符号16位整数 |
System.UInt16 | ushort | 0 ~ 65,535 | 无符号16位整数 |
System.Int32 | int | -2,147,483,648 ~ 2,147,483,647 | 有符号32位整数 |
System.UInt32 | uint | 0 ~ 4,294,967,295 | 无符号32位整数 |
System.Int64 | long |
-9,223,372,036,854,775,808 ~
9,223,372,036,854,775,807
| 有符号64位整数 |
System.UInt64 | ulong | 0 ~ 18,446,744,073,709,551,615 | 无符号64位整数 |
System.Single | float | ±1.5 × 10-45 ~ ±3.4 × 1038 (7位有效数字) | 32位单精度浮点数 |
System.Double | double | ±5.0 × 10-324 到 ±1.7 × 10308 (15至16位有效数字) | 64位双精度浮点 |
System.Decimal | decimal | ±1.0 × 10-28 到 ±7.9 × 1028 (27至28位有效数字) | 128位浮点数数 |
System.String | string | 任意字符串 | / |
以上类型的对象在C#中都可以使用“常量”来表示。例如常量”Hello”表示一个string类型的对象。
上述元类型还有一个特点,即除了string类型外,其它均为值类型。
二、值类型:
学习过C语言的同学应该清楚,在C语言中,存在有两处重要的数据存储内存空间:栈和堆。栈是一个FILO类型的数据结构,用于存放变量,例如:
堆是一个链式数据结构,用于分配任意大小内存空间,例如:
前者称为值类型变量,后者称为指针类型变量。
C语言书籍中对这两类变量有如下一段说明:栈内存结构可以快速的分配内存和回收内存,但栈内存空间有限,过分使用会发生“溢出”,所以栈用于分配常用的,占用空间较小的数据类型;堆内存结构分配内存较慢,但可利用空间较大,可以存放大型数据。
在C#中,几乎所有的数据都存储在“堆”结构中,并且这个堆受到.net垃圾回收机制监控,称为“托管堆”,虽然.net的堆结构经过改良,内存分配效率要高于C语言的堆,但相对于栈,其效率仍显低下。并且为了能够正确的垃圾回收,每一次分配的堆空间要较实际需要空间略大,所以在小型数据上使用堆是得不偿失的。
C#提供了一种特殊的类,值类型类,用来声明分配在栈上的对象。看如下范例:
通过上述例子,我们可以得出值类型的几个特点:
- 值类型类使用struct关键字声明;
- 值类型类不能继承自其它类(除了Object类以外),但可以实现一个或多个接口;
- 值类型类使用值类型作为字段类型,值类型类的字段无法具有默认值;
- 值类型类有且必须具备编译器提供的默认构造器,且无法手动定义;值类型可以具有参数构造器,但不会因为具有参数构造器而失去编译器提供的默认构造器,在值类型构造器中,可以直接访问类中的字段,但无法访问类中的属性和方法;
- =运算符对于值类型,是值的赋值而非引用的传递;值类型变量不能为null,因为值类型变量必须有值而非引用。值类型中不存在引用的概念;
最为重要的一点:值类型的=是值得复制而非引用的传递,所以值类型赋值是值的传递,当值从一个变量传递到另一个变量后,这两个变量之间就没有任何联系了。这一点和引用类型非常不同。注意上述两段代码,第一段代码的66-72行和第二段代码的64-70行,查看运行结构,思考原因。
因为值类型变量无法被初始化为null值,所以一般来说值类型类都提供一个公共只读静态字段Empty(只读字段使用readonly关键字声明,后面详细介绍)。这个静态只读量初始化为一个对于这个值类型来说的无效值。用于初始化一个表示“空”的值类型变量。