### 一、数 据 类 型
C#的数据类型分成两大类:一类是值类型(Value
Types),另一类是引用类型(Reference
Types)。每一大类又可再分成几个小类,如图2.1所示。

#### 1.值 类 型
所谓值类型就是一个包含实际数据的变量。当定义一个值类型变量时,C#会根据所声明的类型,以堆栈方式分配一块大小相适应的存储区域给这个变量,对这个变量的读/写操作就直接在这块存储区域进行。
C#中的值类型包括:简单类型、枚举类型和结构类型。
例如:
```C#
int iNum=10; // 分配一个32位内存区域给变量iNum,并将10放入该内存区域
iNum=iNum+10; // 从变量iNum中取出值,加上10,再将计算结果赋给iNum
```
简单类型是系统预置的,一共有13个,如表2.1所示。
| C#关键字 | .NET CTS类型名 | 说 明 | 范围和精度 |
| -------- | -------------- | ----------------------- | ---------------------------------------------------------- |
| bool | System.Boolean | 逻辑值(真或假) | true, false |
| sbyte | System.SByte | 8位有符号整数类型 | -128~127 |
| byte | System.Byte | 8位无符号整数类型 | 0~255 |
| short | System.Int16 | 16位有符号整数类型 | -32 768~32 767 |
| ushort | System.UInt16 | 16位无符号整数类型 | 0~65 535 |
| int | System.Int32 | 32位有符号整数类型 | -2 147 483 648~2 147 483 647 |
| uint | System.Uint32 | 32位无符号整数类型 | 0~4 294 967 295 |
| long | System.Int64 | 64位有符号整数类型 | -9 223 372 036 854 775 808~9 223 372 036 854 775 807 |
| ulong | System.UInt64 | 64位无符号整数类型 | 0~18 446 744 073 709 551 615 |
| char | System.Char | 16位字符类型 | 所有的Unicode编码字符 |
| float | System.Single | 32位单精度浮点类型 | ±1.5´10-45 ~ ±3.4´1038 (大约7个有效十进制数位) |
| double | System.Double | 64位双精度浮点类型 | ±5.0´10-324 ~ ±3.4´10308 (大约15~16个有效十进制数位) |
| decimal | System.Decimal | 128位高精度十进制数类型 | ±1.0´10-28 ~ ±7.9´1028 (大约28~29个有效十进制数位) |
表2.1中“C#关键字”是指在C#中声明变量时可使用的类型说明符。
例如:
```C#
int myNum // 声明myNum为32位的整数类型
```
.NET平台包含所有简单类型,它们位于.NET框架的System名字空间。C#的类型关键字就是.NET中所定义类型的别名。从表2.1可见,C#的简单数据类型可分为整数类型(包括字符类型)、实数类型和布尔类型。
(1)整数类型
该类型共有9种,它们的区别在于所占存储空间的大小,有无符号位及所能表示的数的范围,这些是程序设计时定义数据类型的重要参数。char类型归属于整数类别,但它与整数类型有所不同,不支持从其他类型到 char 类型的隐式转换。
(2)实数类型
该类型有3种,其中浮点类型float、double关键字采用IEEE 754格式来表示,因此浮点运算一般不会产生异常。decimal 类型主要用于财务和货币计算,它可以精确地表示十进制小数(如0.001)。虽然它具有较高的精度,但取值范围较小,因此从浮点类型到 decimal 的转换可能会产生内存溢出异常;而从decimal到浮点类型的转换则可能导致精度的损失,所以浮点类型与decimal之间也不存在隐式转换。
(3)布尔类型
该类型表示布尔逻辑量,它与其他类型之间不存在标准转换,即不能用一个整型数表示true或false,反之亦然,这点与C/C++不同。
#### 2.引用类型
一个引用类型的变量不存储它们所代表的实际数据,而是存储实际数据的引用。引用类型分3步创建:首先在栈内存上创建一个引用变量,然后在堆内存上创建对象本身,最后把这个对象所在内存的句柄(首地址)赋给引用变量。
例如:
```C#
string s1, s2;
s1="ABCD";
s2 = s1;
```
其中,s1、s2都是指向字符串“ABCD”的引用变量,s1的值是“ABCD”存放在内存中的**地址**(即引用),两个引用型变量之间的赋值,使得s2、s1都成为对“ABCD”的引用,如图2.2所示。

### 二、装箱与拆箱
#### 1.装箱
所谓“装箱”就是将值类型包装成引用类型的过程。当一个值类型被要求转换成一个object 对象时,“装箱”操作自动进行:首先创建一个对象实例,然后把值类型的值复制到其中,最后由 object引用这个对象实例。
例如:
```C#
int x = 123;
object obj1=x; // 装箱操作
x = x+100; // 改变x的值时,obj1的值并不会随之改变
Console.WriteLine (" x= {0}" , x ); // x=223
Console.WriteLine (" obj1= {0}" , obj1 ); // obj1=123
```
上段代码的操作机制,如图2.3所示。

#### 2.拆箱
“拆箱”操作与“装箱”相反,是将一个object转换成值类型:首先检查由object引用的对象实例值类型的包装值,然后把实例中的值复制到值类型变量中。
例如:
```c#
int x = 123, y;
object obj1=x; // 装箱操作
y = (int) obj1; // 拆箱操作,必须进行强制类型转换
Console.WriteLine (" y= {0}" , y ); // y=123
```
【例**2.1**】 编写程序,以探索C#两大类数据类型的[性质及其相互转换机制。]([例2.1] 编写程序.txt)

### 三、常量
#### 1.整数常量
对于一个整数值,默认的类型就是能保存它的最小整数类型,其类型分为 int、uint、long或 ulong。如果默认类型不是需要的类型,可以在常量后面加上后缀(U 或 L)来明确指定其类型。
在常量后面加L或l(不区分大小写)表示长整型。例如:
```
32 // 这是一个int类型
32L // 这是一个long类型
```
在常量后面加U或u(不区分大小写)表示无符号整数。例如:
```
128U // 这是一个uint 类型
128UL // 这是一个ulong类型
```
整型常量既可以采用十进制数也可以采用十六进制数(默认为十进制数)表示,在数值前面加0x(或0X)则表示十六进制数,基数用0~9、A~F(或a~f),例如:
```
0x20 // 十六进制数20,相当于十进制数32
0x1F // 十六进制数1F,相当于十进制数31
```
#### 2.浮点常量
一般带小数点的数或用科学计数法表示的数都被认为是浮点数,它的数据类型默认为double类型,但也可以加上后缀符表明三种不同的浮点格式数。
在数字后面加上F(f)表示是float类型。
在数字后面加上D(d)表示是double类型。
在数字后面加上M(m)表示是decimal类型。
例如:
```
3.14 , 3.14e2, 0.618E2 // 这些都是double类型常量,其中3.14e2相当于3.14×102
// 0.618E2 相当于
3.14F, 0.618f // 这些都是float类型常量
3.14D, 0.618d // 这些都是double类型常量
3.14M, 0.618m // 这些都是decimal类型常量
```
#### 3.字符常量
字符常量,简单地说,就是用单引号括起来的单个字符(如'A'),它占16位,以无符号整型数的形式存储这个字符所对应的Unicode代码。这对于大多数图形字符是可行的,但对一些非图形的控制字符(如回车符)则行不通,所以字符常量的表达有若干种形式。
单引号括起的一个字符,如'A'。
十六进制的换码系列,以“\x”或“\X”开始,后面跟4位十六进制数,如' \X0041' 。
Unicode码表示形式,以“\U”或“\u”开始,后面跟4位十六进制数,如' \U0041'。
显式转换整数字符代码,如(char)65。
转义字符系列,如表2.2所示。
| 转 义 字 符 | 含 义 | Unicode码 | 转 义 字 符 | 含 义 | Unicode码 |
| ------------- | ---------- | --------- | ------------- | ---------- | --------- |
| \' | 单引号 | \u0027 | \b | 退格符 | \u0008 |
| \" | 双引号 | \u0022 | \f | 走纸换页符 | \u000C |
| \\ | 反斜线字符 | \u005C | \n | 换行符 | \u000A |
| \0 | 空字符 | \u0000 | \r | 回车符 | \u000D |
| \a | 警铃符 | \u0007 | \t | 水平制表符 | \u0009 |
| \v | 垂直制表符 | \u000B | | | |
#### 4.字符串常量
(1)常规字符串
双引号括起的一串字符,可以包括转义字符。
例如:
```
"Hello, World\n"
"C:\\windows\\Microsoft" // 表示字符串 C:\windows\Microsoft
```
(2)逐字字符串
在常规的字符串前加上一个@,就形成了逐字字符串。它的意思是字符串中的每个字符均表示本意,不使用转义。如果在字符串中需用到双引号,则可连写两个双引号来表示一个双引号。
例如:
```
@"C:\windows\Microsoft" // 与 "C:\\windows\\Microsoft" 含义相同
@"He said""Hello"" to me" // 与"He said\"Hello\" to me" 含义相同
```
#### 5.布尔常量
它只有两个值:true和false。
#### 6.符号常量
在声明语句中,可以声明一个标识符常量,但必须在定义标识符时就进行初始化,并且定义之后就不能再改变该常量的值。
具体的格式为:
```
const 类型 标识符=初值
```
例如:
```
const double PI=3.1416
```
### 四、变量
C#中的变量必须先声明后使用,包括声明变量的名称、数据类型,必要时指定变量的初始值。
声明变量的形式:
```
类型 标识符[=初值] [ ,…];
```
标识符必须以字母或者_(下画线)开头,后面跟字母、数字和下画线的组合。例如,name、_Int、Name、x_1等都是合法的标识符,但C#是大小写敏感的语言,name和Name分别代表不同的标识符,在定义和使用时要特别注意。另外,变量名不能与 C#中的关键字相同,除非标识符是以@作为前缀的。
例如:
```
int x ; // 合法
float y1=0.0, y2 =1.0, y3 ; // 合法,变量声明的同时可以指定初始值
string char // 不合法,因为char是关键字
string @char // 合法
```
### 使用举例
【例2.2】 编写程序,测试C#各种常量与变量的用法。
运行程序,结果如图2.5所示。
