数据类型
任何编程语言都有数据类型的概念,这些数据类型大体可分为字符串、文本、数字、日期等等。下图就是C#中数据类型的继承关系图。
在这个结构图中所有的以“System”开头的都属于基础数据类型,其他的都是自定义数据类型。
基础数据类型
System.Object类型
该类型表示C#数据类型体系中最为基础的类型,在C#中使用关键字“object”表示该类型。
C#的数据类型体系和其他编程语言的最大的不同就是实现了各种数据类型的统一,并提供了一个所有数据类型的基础类型,那就是在命名空间System下面的Object类型。
在其他编程语言,比如VB,其整数、浮点数等基础类型都是原子类型,不是从其他类型派生的,但C#是彻彻底底的实现了面向对象编程,即使这些技术类型都是从Object类型派生过来的,而Object类型就是最基础的类,再往上就没有类型了。
Object类型提供一些成员方法,最常见的有
Equals |
带一个参数,用于对两个对象数据进行比较,若相等则返回True,否则返回False。 |
Finalize |
在自动回收对象之前执行清理操作,该方法一般由.NET框架自动调用。 |
GetHashCode |
生成一个与对象的值相对应的数字以支持哈希表的使用。 |
ToString |
生成描述对象数据的字符串。一般供人阅读。 |
在Object类型上C#使用以下基础数据类型,而且有很多基础数据类型在C#有对应的关键字表示。
类型 |
对应的 |
说明 |
System.Boolean |
bool |
布尔类型,其值只能为true或false,该数据类型占用1个字节内存。 |
System.Byte |
byte |
表示一个从0到255的整数,该数据类型占用1个字节内存。 |
System.SByte |
sbyte |
表示一个从-127到127的整数,占用1个字节, |
System.Char |
char |
表示一个字符数据,占用2个字节。和C语言类似,Char类型可以强制转换为整数。这个字符数据是采用Unicode编码格式。 |
System.Int16 |
short |
表示一个从 -32768 到 +32767 的整数,占用2个字节。 |
System.UInt16 |
ushort |
表示一个从0 和 65535的整数,占用2个字节。 |
System.Int32 |
int |
表示一个从-2,147,483,648(约负21亿) 到 +2,147,483,647(约21亿)的整数,占用4个字节。 |
System.UInt32 |
uint |
表示一个从0 到 4,294,967,295 之间的整数,占用4个字节。 |
System.Int64 |
long |
表示一个从-9,223,372,036,854,775,808 到 +9,223,372,036,854,775,807的整数,占有8个字节。 |
System.UInt64 |
ulong |
表示一个从0 到 18,446,744,073,709,551,615的整数,占用8个字节。 |
System.Single |
float |
表示一个从-3.402823e38 和 +3.402823e38 之间的单精度浮点数字,有7位有效数字。占用4个字节。 |
System.Double |
double |
表示一个-1.79769313486232e308 和 +1.79769313486232e308 之间的浮点数,有15位有效数字,占用8个字节。 |
System.Decimal |
decimal |
表示一个从+79,228,162,514,264,337,593,543,950,335 到 -79,228,162,514,264,337,593,543,950,335之间的数字。而且计算时尽量不进行舍入操作,这样能维护运算精度,比较适合财务运算。 |
System.DateTime |
无 |
表示一个从公元(基督纪元)0001 年 1 月 1 日午夜 12:00:00 到公元 (C.E.) 9999 年 12 月 31 日晚上 11:59:59 之间的时间日期数据,精确到100纳秒。 在初始化日期数据的时候,可以传递年数、月份数和日数,也可以继续添加24小时制的小时数、分钟数和秒数。 以下代码就定义了一个DateTime类型。 DateTime dtm = new DateTime( 1980 , 2 , 14 ); 也可以为 DateTime dtm2 = new DateTime( 1980 , 2 , 14 , 16, 23 , 39 ); |
System.String |
string |
表示一段文本,采用UTF-16编码,可以包含字符“\0”。 |
System.Enum |
enum |
所有枚举类型的基础类型。 |
System.Deleate |
delegate |
所有委托类型的基础类型。 |
Syatem.Array |
无 |
所有数组类型的基础类型。 |
数组
C#支持数组,它包含着若干干相同类型的变量。在C#代码中,使用“type[] arrayName”的方式来定义数组,比如以下代码定义了几个数组
int[ ] ids = null; // 定义了一个整数数组 string[ ] names = new string[ 100 ]; // 定义了一个字符串数组,并初始化为包含100个数据。 |
在初始化数组时,数组里的元素值也初始化了,对于bool类型的数组,其元素值初始化为false,数值型的初始化为0,字符串的初始化为null。
在C#中数组的下标是从0开始的,可以使用数组对象的Length属性获得数组的长度,比如以下代码就是遍历数组所有的元素。
string[ ] names = new string[100]; for (int iCount = 0; iCount < names.Length; iCount++) { string name = names[iCount]; } |
也可以使用foreach语句来遍历数组中所有的元素。如下所示
string[ ] names = new string[100]; foreach( string name in names ) { // 此处可以使用变量“name”的值 } |
注意在for循环中可以通过修改“names[ iCount ]”的值来修改数组中存储的数据;但在foreach循环中,name不能修改,是只读的。
在初始化结构体类型的数组时,数组是有效的,而且数组中的元素也是有效的;而在初始化类类型的数组时,虽然数组是有效的,但其数组的元素全部为空引用。
例如以下代码定义了结构体类型MyPeopleStruct。
public struct MyPeopleStruct { public string Code; public string Name; } |
针对该类型执行以下代码是不会出事的
MyPeopleStruct[] peoples = new MyPeopleStruct[100]; peoples[33].Name = "张三"; |
因为结构体数组初始化后,系统会自动创建数组元素对象。
若以下代码定义了类类型MyPeopleClass。
public class MyPeopleClass { public string Code = null; public string Name = null; } |
若有以下代码
MyPeopleClass[] peoples = new MyPeopleClass[100]; peoples[3].Name = "张三"; |
这段代码可以编译通过,但运行时会在代码“peoples[3].Name = "张三"”处报空引用的程序错误。这是因为初始化了类类型数组,只是为数组分配了内存空间,但没有相应的创建对象类型,该数组的元素全部设置为空引用,对于空引用调用其成员就会报空引用错误。
空引用错误是C#程序中最常见的错误。
自定义类型
在程序开发中个,仅仅使用这些基础数据类型是不够的,还需要开发人员根据需要自定义数据类型。在C#中,自定义的数据类型有类、结构体、枚举和委托。
类类型
在C#中使用关键字“class”定义的类型为类类型,以下代码就定义了一个类类型。
public class PeopleClass { public PeopleClass() { }
private string _Name = null; public string Name { get { return _Name; } set { _Name = value; } } public override string ToString() { return _Name; } } |
在代码“public class PeopleClass”中,关键字“public”说明该类型是公开的;“class”说明这是一个类类型;“PeopleClass”指定了类型的名称。
类类型是引用类型,比如执行了以下代码
PeopleClass p1 = new PeopleClass(); p1.Name = "张三"; People p2 = p1 ; p2.Name = "李四"; |
则代码执行后,变量p1和p2指向的是同一个对象,也可以理解为指向同一个内存地址,很显然,通过变量p2修改值和通过p1修改其效果是一样的,这样p1.Name和p2.Name的值都等于“李四”。
结构体类型
C#支持结构体类型,以下代码就定义了一个结构体类型。
public struct PeopleStruct { public string Code; public string Name; public bool Sex; } |
这段代码定义了一个名为People的结构体,它有“Code”、“Name”、“Sex”三个公开字段。我们可以使用一下的代码来使用这个结构体类型。
PeopleStruct myPeople = new PeopleStruct( ); myPeople.Code = “1000”; myPeople.Name = “张三”; |
结构体类型中可以定义字段、属性、方法和事件,但和类类型有着以下区别
●结构体中字段不能初始化,比如在结构体中需要写成“public string Code;”,而在类类型中可以写成“public string Code = null;”。
●结构体中不能定义默认的构造函数(无参数的构造函数)。
●结构体可以定义带参数的构造函数,但在函数体中在执行任何代码前必须对所有的字段进行赋值初始化。
●结构体对象在赋值时会重新创建一个对象并复制所有的字段值。对新结构体的数据的修改不会影响原始对象的内容。比如对于结构体类型People执行了以下代码
People p1 = new People(); p1.Name = "张三"; People p2 = p1 ; p1.Name = "李四"; |
则p2.Name的值还是为“张三”。
●结构体不能继承自其他结构体类型,也不能派生新的结构类型。所有的结构体类型直接继承自类型System.ValueType。
●结构体可以实现接口。
枚举类型
C#支持枚举类型,以下代码就定义了一个枚举类型。
public enum BarcodeStyle { Code128A, Code128B, Code128C } |
在C#中,枚举变量是可以转换为整数的,第一个枚举成员默认等于0,然后依次增加,不过也可以明确的设置枚举成员数值。例如上述代码等价于
public enum BarcodeStyle { Code128A = 0 , Code128B = 1, Code128C = 2 } |
这个设置数值是比较自由的,可以任意指定,比如可以使用以下代码定义枚举类型。
public enum FlagStyle { Flag1 = 1 , Flag2 = 4, Flag3 = 64 } |
所有的枚举类型都是从基础类型System.Enum派生的。System.Enum类型提供了一些能用于所有枚举类型的方法,常用的有
GetName |
获得等于指定数据的枚举项目的名称。该函数是静态的,具有两个参数,第一个是枚举类型,第二个是某个常数。 例如对于上面的BarcodeStyle枚举类型,执行代码“Enum.GetName( typeof( BarcodeStyle ) , 0 ) ”,就返回字符串“Code128A”;执行“Enum.GetName( typeof( BarcodeStyle” , 1 )”就返回字符串“Code128B”。 |
|
GetNames |
获得枚举类型的所有枚举项目的名称组成的字符串数组。该函数时静态的,参数就是枚举类型变量。 例如对于BarcodeStyle枚举类型,执行代码“Enum.GetNames(typeof( BarcodeStyle ))”就返回一个字符串数组,数组元素是“Code128A”、“Code128B”、“Code128C”。 |
|
GetValues |
获得枚举类型的所有枚举项目组成的数组。该函数是静态的,参数就是枚举类型变量。 例如对于BarcodeStyle类型,执行代码“Enum.GetValues( typeof( BarocdeStyle ))”就返回一个数组,数组元素就是“BarcodeStyle.Code128A”、“BarcodeStyle.Code128B”、“BarcodeStyle.Code128C”。 |
|
Parse |
解析字符串并转化为枚举类型,若转化失败则会抛出异常。该函数时静态的,参数是指定的枚举类型和要解析的字符串,此外还有第三个布尔类型的可选参数,用于指明是否区分大小写。 例如对于BarcodeStyle类型,执行代码“Enum.Parse( typeof( BarcodeStyle ) , “Code128A” )”就返回“BarcodeStyle.Code128A”。 执行代码“Enum.Parse( typeof( BarcodeStyle ) , “code128a”, true)”也返回“BarcodeStyle.Code128A”。 注意,当解析失败时,该函数会抛出异常。 |
|
TryParse |
解析字符串并试图将其转化为枚举类型,如转化失败则不抛出异常,该函数返回转化是否成功的布尔值。该函数是静态的,第一个参数就是要转化的字符串,第二个可选参数就是转化时是否区分大小写,第三个参数就是保存转化结果的枚举变量。 例如对于“BarcodeStyle”,调用代码“Enum.TryParse( “Code128A” , out value )”,则函数返回true而且value值被设置成“BarcodeStyle.Code128A”;调用代码“Enum.TryParse(“abc” , out value )”,则函数返回false,表明转化失败。 |
|
|