4.3 数据类型
C#是一种强类型语言,无论是变量、常量,还是方法的参数、返回值,都需要指定相应的数据类型。从某种意义上来说,数据类型就像数据结构的模板,它包含了很多信息:
❑一种数据类型所需要的内存空间;
❑该数据类型的取值范围,即它可以表示的最大值和最小值;
❑它所继承的基类信息;
❑运行时它在内存中存储的位置;
❑该数据类型本身所支持的操作,比如数字型支持四则运算;
❑它自身的成员,如方法、字段、事件,等等。
编译器依赖数据类型来实现类型安全,比如可以对数字型变量实施加减操作,但无法对布尔型执行同样的操作。另外,编译器将数据类型作为元数据放入编译生成的程序集中,进一步保证程序中运行时依赖相应的数据类型进行正确的内存分配和回收,进一步保证类型安全性。
我们在第1章学习了CTS和CLS,知道了.NET框架已经帮我们定义了大量的基本数据类型,对应表4-2,我们可以看到C#的数据类型和.NET框架数据类型的对应关系,事实上,C#的内置类型关键字只不过是CTS中预定义类型的一个别名而已,它们是等价的,如表4-2所示。
在表4-2中,除了object和string类型外,其他类型都称为简单类型。
因为C#内置类型的关键字就是CTS类型的别名,因此在使用时它们可以互换,而使用CTS类型的别名显然要省事得多,如代码清单4-7所示。
代码清单4-7 C#类型关键字和CTS类型的关系
int Age=10;
System.Int32 Count=20;
我们知道,CTS中的类型只有值类型和引用类型两种,包括.NET框架预定义的BCL类库和我们自定义的类、接口等,如图4-4所示。
图 4-4 CTS中的值类型和引用类型
下面我们从值类型和引用类型两方面来分析C#语言的内置类型。
4.3.1 内置的值类型
首先通过一幅图来看看C#语言中的值类型包含哪些类型,如图4-5所示。
图 4-5 C#语言中内置的值类型
由图4-5可以看出,值类型主要由两大类型组成:结构类型[1]和枚举类型[2]。而我们平时常用的数值型、布尔型都是结构类型,其中数值型又包括:整型、浮点型和十进制型,下面将分别介绍。
1.整型
正确的使用类型是很重要的,我们先通过表4-3了解整型所包含的类型,以及它们的取值范围和长度信息,然后对每个类型逐一介绍。
(1)sbyte
sbyte关键字表示整数数据类型,它存储的值如表4-4所示。
声明和使用sbyte类型的变量:
sbyte val=100;
(2)byte
sbyte关键字表示整数数据类型,它存储的值如表4-5所示。
声明和使用byte类型的变量:
byte val=100;
(3)char
char关键字用于声明一个Unicode字符,它存储的值如表4-6所示。Unicode字符是16位字符,用于表示世界上已知的绝大多数书面语言。
对char关键字的使用举例如下:
char[]chars=new char[4];
chars[0]='X';//字符
chars[1]='\x0058';//16进制
chars[2]=(char)88;//从数值型转换
chars[3]='\u0058';//Unicode
foreach(char c in chars)
{
Console.Write(c+“");
}
上述代码的输出结果为:X X X X。
(4)short
short关键字表示整数数据类型,它存储的值如表4-7所示。
short的用法如下:
short val=12345;
(5)ushort
ushort关键字表示整数数据类型,它存储的值如表4-8所示。
ushort的用法如下:
ushort ushortVal=65535;
(6)int
int关键字表示整数数据类型,它存储的值如表4-9所示。
int的用法如下:
int iVal=65535;
(7)uint
uint关键字表示整数数据类型,它存储的值如表4-10所示。
uint的用法如下:
uint theUint=967295;
(8)long
long关键字表示整数数据类型,它存储的值如表4-11所示。
long的声明有如下几种方式:
long longValue1=4294967296;
long longValue2=4294967296L;//后缀'L'
long longValue3=4294967296l;//后缀'l',和大写'L'等价
注意虽然后缀使用大写的"L"和小写的"l"均可,但小写的"l"易和数字"1"混淆,因此为了不引起混淆,建议使用大写的"L"做后缀。
(9)ulong
ulong关键字表示整数数据类型,它存储的值如表4-12所示。
ulong的用法如下:
ulong uLong=9223372036854775808;
如果整数没有后缀,则其类型为以下类型中可表示其值的第一个类型:int、uint、long、ulong。在上面的示例中,它是ulong类型。
还可根据以下规则使用后缀指定文字类型:
❑如果使用L或l,那么根据整数的大小,可以判断出其类型为long还是ulong。
❑如果使用U或u,那么根据整数的大小,可以判断出其类型为uint还是ulong。
❑如果使用UL、ul、Ul、uL、LU、lu、Lu或lU,则整数的类型为ulong。
2.浮点型
浮点型分为单精度浮点数(float)和双精度浮点数(double),如表4-13所示。
(1)float
float关键字表示存储32位浮点值的简单类型,它存储的值的精度和大致范围如表4-14所示。
默认情况下,赋值运算符右侧的实数被视为double类型。因此,应使用后缀f或F初始化浮点型变量,如以下示例所示:
float x=3.14F;
注意 如果在以上声明中不使用后缀,则会因为你试图将一个double值存储到float变量中而发生编译错误:Literal of type double cannot be implicitly converted to type'float';use an'F'suffix to create a literal of this type.
(2)double
double关键字表示存储32位浮点值的简单类型,它存储的值的精度和大致范围如表4-15所示。
默认情况下,赋值运算符右侧的实数被视为double。但是,如果希望整数被视为double,请使用后缀d或D,例如:
double x=10d;
3.十进制型
表4-16给出了十进制型的大致范围和精度。
decimal关键字表示整数数据类型,它存储的值如表4-17所示。
如果希望实数被视为decimal类型,请使用后缀m或M,例如:
decimal myMoney=1023.5m;
注意 如果没有后缀m,数字将被视为double类型,从而导致编译器错误。
4.布尔型
bool关键字是System.Boolean的别名,用于声明变量来存储布尔值true和false。
注意 如果需要一个可以为null的布尔型变量,可以使用bool?
可将布尔值赋给bool变量。也可以将计算为bool类型的表达式赋给bool变量,如下所示。
bool isArrived=false;
int speed=120;
bool isOverSpeed=speed>100;
if(!isArrived&&isOverSpeed)
{
Console.WriteLine(“你超速了!请注意安全!”);
}
5.自定义结构类型
struct类型是一种值类型,如果需要一个用于存储数据并且数据量较小的类型时,通常使用结构类型,例如,矩形的坐标或库存商品的特征。下面的示例显示了一个简单的结构声明。
public struct Point
{
public int X;
public int Y;
}
6.BigInteger和Complex
这两个类型都是在.NET 4中新增的,它们位于System.Numerics命名空间。表4-18是对它们的说明。
(1)BigInteger
BigInteger类型是不可变类型,代表一个任意大的整数,其值在理论上已没有上部或下部的界限。此类型不同于.NET Framework中的其他整型,后者已通过其MinValue和MaxValue属性指示了一个范围。因为它没有没有上限或下限,对于导致BigInteger值增长过大的任何操作都会引发内存溢出异常——OutOfMemoryException。
代码清单4-8 是使用了BigInteger类型的示例代码。
代码清单4-8 BigInteger的使用示例
using System;
namespace ProgrammingCSharp4
{
class BigIntegerSample
{
static void Main(string[]args)
{
System.Numerics.BigInteger googol=
System.Numerics.BigInteger.Pow(10,100);
Console.WriteLine(googol.ToString());
}
}
}
上述代码的运行结果如所示:
10000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000
请按任意键继续……
要使用BigInteger类,需要手动添加对System.Numerics的引用,如图4-6所示。
图 4-6 添加对System.Numerics的引用
(2)Complex
Complex表示一个复数,我们知道,复数由实数部分和虚数部分组成。在实例化和操作复数时,Complex类型使用笛卡尔坐标系统(实数,虚数)。一个复数可以表示为一个二维坐标系中的某个点。复数的实数部分位于x轴(水平轴),虚数部分位于y轴(垂直轴)。
代码清单4-9 是使用了Complex类型的示例代码。
代码清单4-9 Complex类型示例代码
using System;
using System.Numerics;
namespace ProgrammingCSharp4
{
class BigIntegerSample
{
static void Main(string[]args)
{
var z1=new Complex(6,6);
var z2=new Complex(8,8);
var r1=Complex.Add(z1,z2);
var r2=Complex.Subtract(z1,z2);
var r3=Complex.Multiply(z1,z2);
var r4=Complex.Divide(z1,z2);
Console.WriteLine("Z1+Z2:"+r1);
Console.WriteLine("Z1-Z2:"+r2);
Console.WriteLine("Z1×Z2:"+r3);
Console.WriteLine("Z1÷Z2:"+r4);
}
}
}
上述代码的运行结果如下:
Z1+Z2:(14,14)
Z1-Z2:(-2,-2)
Z1×Z2:(0,96)
Z1÷Z2:(0.75,0)
请按任意键继续……
[1]结构类型在第13章详述。
[2]枚举类型在第14章详述。