04 C# 类型Word文档下载推荐.docx
《04 C# 类型Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《04 C# 类型Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。
一个值类型或是结构类型,或是枚举类型。
C#提供称为简单类型(simpletype)的预定义结构类型集。
简单类型通过保留字标识。
value-type:
struct-type
enum-type
struct-type:
type-name
simple-type
simple-type:
numeric-type
bool
numeric-type:
integral-type
floating-point-type
decimal
integral-type:
sbyte
byte
short
ushort
int
uint
long
ulong
char
floating-point-type:
float
double
enum-type:
值类型的变量总是包含该类型的值。
与引用类型不同,值类型的值不可能为null,也不可能引用派生程度较大的类型的对象。
值类型的变量赋值会创建所赋的值的一个副本。
这不同于引用类型的变量赋值,引用类型的变量赋值复制的是引用而不是由引用标识的对象。
1.1.1System.ValueType类型
所有值类型从类System.ValueType隐式继承,后者又从类object继承。
任何类型都不可能从值类型派生,因此,所有值类型都是隐式密封的(第10.1.1.2节)。
注意,System.ValueType本身不是value-type。
相反,它属于class-type,所有value-type都从它自动派生。
1.1.2默认构造函数
所有值类型都隐式声明一个称为默认构造函数(defaultconstructor)的公共无参数实例构造函数。
默认构造函数返回一个零初始化实例,它就是该值类型的默认值(defaultvalue):
∙对于所有simple-types,默认值是将其所有位都置零的位模式所形成的值:
o对于sbyte、byte、short、ushort、int、uint、long和ulong,默认值为0。
o对于char,默认值为'
\x0000'
。
o对于float,默认值为0.0f。
o对于double,默认值为0.0d。
o对于decimal,默认值为0.0m。
o对于bool,默认值为false。
∙对于enum-typeE,默认值为0。
∙对于struct-type,默认值是通过将所有值类型字段设置为它们的默认值、将所有引用类型字段设置为null而产生的值。
与任何其他实例构造函数一样,值类型的默认构造函数也是用new运算符调用的。
出于效率原因,实际上,不必故意调用它的构造函数。
在下面的示例中,变量i和j都被初始化为零。
classA
{
voidF(){
inti=0;
intj=newint();
}
}
由于每个值类型都隐式地具有一个公共无参数实例构造函数,因此,一个结构类型中不可能包含一个关于无参数构造函数的显式声明。
但允许结构类型声明参数化实例构造函数(第11.3.8节)。
1.1.3结构类型
结构类型是一种值类型,它可以声明常量、字段、方法、属性、索引器、运算符、实例构造函数、静态构造函数和嵌套类型。
有关结构类型的介绍详见第11节。
1.1.4简单类型
C#提供称为简单类型的预定义结构类型集。
简单类型通过保留字标识,而这些保留字只是System命名空间中预定义结构类型的别名,详见下表。
保留字
化名的类型
System.SByte
System.Byte
System.Int16
System.UInt16
System.Int32
System.UInt32
System.Int64
System.UInt64
System.Char
System.Single
System.Double
System.Boolean
System.Decimal
由于简单类型是结构类型的别名,每个简单类型都具有成员。
例如,int具有在System.Int32中声明的成员以及从System.Object继承的成员,允许使用下面的语句:
inti=int.MaxValue;
//System.Int32.MaxValueconstant
strings=i.ToString();
//System.Int32.ToString()instancemethod
stringt=123.ToString();
简单类型与其他结构类型的不同之处在于:
简单类型允许某些附加的操作:
∙大多数简单类型允许通过编写literals(第2.4.4节)来创建值。
例如,123是类型int的文本,'
a'
是类型char的文本。
C#没有普遍地为结构类型设置类似的以文本创建值的规则,所以其他结构类型的非默认值最终总是通过这些结构类型的实例构造函数来创建的。
∙当表达式的操作数都是简单类型常量时,编译器可以在编译时计算表达式。
这样的表达式称为constant-expression(第7.15节)。
涉及其他结构类型所定义的运算符的表达式不被视为常量表达式。
∙通过const声明可以声明简单类型(第10.3节)的常量。
常量不可能属于其他结构类型,但staticreadonly字段提供了类似的效果。
∙涉及简单类型的转换可以参与由其他结构类型定义的转换运算符的计算,但用户定义的转换运算符从来不能参与其他用户定义运算符的计算(第6.4.2节)。
1.1.5整型
C#支持9种整型:
sbyte、byte、short、ushort、int、uint、long、ulong和char。
整型具有以下所列的大小和取值范围:
∙sbyte类型表示有符号8位整数,其值介于-128和127之间。
∙byte类型表示无符号8位整数,其值介于0和255之间。
∙short类型表示有符号16位整数,其值介于-32768和32767之间。
∙ushort类型表示无符号16位整数,其值介于0和65535之间。
∙int类型表示有符号32位整数,其值介于-2147483648和2147483647之间。
∙uint类型表示无符号32位整数,其值介于0和4294967295之间。
∙long类型表示有符号64位整数,其值介于–9223372036854775808和9223372036854775807之间。
∙ulong类型表示无符号64位整数,其值介于0和184********709551615之间。
∙char类型表示无符号16位整数,其值介于0和65535之间。
char类型的可能值集与Unicode字符集相对应。
虽然char的表示形式与ushort相同,但是一种类型上允许实施的所有操作并非都可以用在另一种类型上。
整型一元运算符和二元运算符总是对有符号32位精度、无符号的32位精度、有符号64位精度或无符号64位精度进行操作:
∙对于一元运算符+和~,操作数转换为T类型,其中T是int、uint、long和ulong中第一个可以完全表示操作数的所有可能值的类型。
然后用T类型的精度执行运算,结果的类型是T类型。
∙对于一元运算符–,操作数转换为类型T,其中T是int和long中第一个可以完全表示操作数的所有可能值的类型。
一元运算符–不能应用于类型ulong的操作数。
∙对于+、–、*、/、%、&
、^、|、==、!
=、>
、<
、>
=和<
=二元运算符,操作数转换为类型T,其中T是int、uint、long和ulong中第一个可以完全表示两个操作数的所有可能值的类型。
然后用T类型的精度执行运算,运算的结果的类型也属于T(对于关系运算符为bool)。
对于二元运算符,不允许一个操作数为long类型而另一个操作数为ulong类型。
∙对于二元运算符<
<
和>
>
,左操作数转换为T类型,其中T是int、uint、long和ulong中第一个可以完全表示操作数的所有可能值的类型。
char类型按分类归属为整型类型,但它在以下两个方面不同于其他整型:
∙不存在从其他类型到char类型的隐式转换。
具体而言,即使sbyte、byte和ushort类型具有完全可以用char类型来表示的值范围,也不存在从sbyte、byte或ushort到char的隐式转换。
∙char类型的常量必须写成character-literal或带有强制转换为类型char的integer-literal。
例如,(char)10与'
\x000A'
是相同的。
checked和unchecked运算符和语句用于控制整型算术运算和转换(第7.5.12节)的溢出检查。
在checked上下文中,溢出产生编译时错误或导致引发System.OverflowException。
在unchecked上下文中将忽略溢出,任何与目标类型不匹配的高序位都被放弃。
1.1.6浮点型
C#支持两种浮点型:
float和double。
float和double类型用32位单精度和64位双精度IEEE754格式来表示,这些格式提供以下几组值:
∙正零和负零。
大多数情况下,正零和负零的行为与简单的值零相同,但某些运算会区别对待此两种零(第7.7.2节)。
∙正无穷大和负无穷大。
无穷大是由非零数字被零除这样的运算产生的。
例如,1.0/0.0产生正无穷大,而–1.0/0.0产生负无穷大。
∙非数字(Not-a-Number)值,常缩写为NaN。
NaN是由无效的浮点运算(如零被零除)产生的。
∙以s
×
m
2e形式表示的非零值的有限集合,其中s为1或−1,m和e由特定的浮点型确定:
对于float类型,为0<
m<
224和−149≤e≤104,而对于double类型,为0<
253和−1075≤e≤970。
非标准化的浮点数被视为有效非零值。
float类型可表示精度为7位、在大约1.5
10−45到3.4
1038的范围内的值。
double类型可表示精度为15位或16位、在大约5.0
10−324到1.7
10308的范围内的值。
如果二元运算符的一个操作数为浮点型,则另一个操作数必须为整型或浮点型,并且运算按下面这样计算:
∙如果一个操作数为整型,则该操作数转换为与另一个操作数的类型相同的浮点型。
∙然后,如果任一操作数的类型为double,则另一个操作数转换为double。
至少用double范围和精度执行运算,结果的类型为double(对于关系运算符则为bool)。
∙否则,至少用float范围和精度执行运算,结果的类型为float(对于关系运算符则为bool)。
浮点运算符(包括赋值运算符)从来不产生异常。
相反,在异常情况下,浮点运算产生零、无穷大或NaN,如下所述:
∙如果浮点运算的结果对于目标格式太小,则运算结果变成正零或负零。
∙如果浮点运算的结果对于目标格式太大,则运算结果变成正无穷大或负无穷大。
∙如果浮点运算无效,则运算的结果变成NaN。
∙如果浮点运算的一个或两个操作数为NaN,则运算的结果变成NaN。
可以用比运算的结果类型更高的精度来执行浮点运算。
例如,某些硬件结构支持比double类型具有更大的范围和精度的“extended”或“longdouble”浮点型,并隐式地使用这种更高精度类型执行所有浮点运算。
只有性能开销过大,才能使这样的硬件结构用“较低”的精度执行浮点运算。
C#采取的是允许将更高的精度类型用于所有浮点运算,而不是强求执行规定的精度,造成同时损失性能和精度。
除了传递更精确的结果外,这样做很少会产生任何可察觉的效果。
但是,在x*y/z形式的表达式中,如果其中的乘法会产生超出double范围的结果,而后面的除法使临时结果返回到double范围内,则以更大范围的格式去计算该表达式,可能会产生有限值的结果(本来应是无穷大)。
1.1.7decimal类型
decimal类型是128位的数据类型,适合用于财务计算和货币计算。
decimal类型可以表示具有28或29个有效数字、从1.0
10−28到大约7.9
1028范围内的值。
decimal类型的有限值集的形式为(–1)s
c
10-e,其中符号s是0或1,系数c由0
≤
296给定,小数位数e满足0
e
28。
decimal类型不支持有符号的零、无穷大或NaN。
decimal可用一个
96位整数配上以10的幂标定的单位(定位小数点)来表示。
对于绝对值小于1.0m的decimal,它的值最多精确到第28位小数。
对于绝对值大于或等于1.0m的decimal,它的值精确到28或29个有效数字。
与float和double数据类型相反,十进制小数数字(如0.1)可以精确地用decimal表示形式来表示。
在float和double表示形式中,这类数字通常变成无限小数,使这些表示形式更容易发生舍入错误。
如果二元运算符的一个操作数为decimal类型,则另一个操作数必须为整型或decimal类型。
如果存在一个整型操作数,它将在执行运算前转换为decimal。
decimal类型值的运算结果是这样得出的:
先计算一个精确结果(按每个运算符的定义保留小数位数),然后舍入以适合表示形式。
结果舍入到最接近的可表示值,当结果同样地接近于两个可表示值时,舍入到最小有效位数位置中为偶数的值(这称为“银行家舍入法”)。
零结果总是包含符号0和小数位数0。
如果十进制算术运算产生一个绝对值小于或等于5
10-29的值,则运算结果变为零。
如果decimal算术运算产生的值对于decimal格式太大,则将引发System.OverflowException。
与浮点型相比,decimal类型具有较高的精度,但取值范围较小。
因此,从浮点型到decimal的转换可能会产生溢出异常,而从decimal到浮点型的转换则可能导致精度损失。
由于这些原因,在浮点型和decimal之间不存在隐式转换,如果没有显式地标出强制转换,就不可能在同一表达式中同时使用浮点操作数和decimal操作数。
1.1.8bool类型
bool类型表示布尔逻辑量。
bool类型的可能值为true和false。
在bool和其他类型之间不存在标准转换。
具体而言,bool类型与整型截然不同,不能用bool值代替整数值,反之亦然。
在C和C++语言中,零整数或浮点值或空指针可以转换为布尔值false,非零整数或浮点值或非空指针可以转换为布尔值true。
在C#中,这种转换是通过显式地将整数或浮点值与零进行比较,或者显式地将对象引用与null进行比较来完成的。
1.1.9枚举类型
枚举类型是具有命名常量的独特的类型。
每个枚举类型都有一个基础类型,该基础类型必须为byte、sbyte、short、ushort、int、uint、long或ulong。
枚举类型的值集和它的基础类型的值集相同。
枚举类型的值并不只限于那些命名常量的值。
枚举类型是通过枚举声明(第14.1节)定义的。
1.2引用类型
引用类型是类类型、接口类型、数组类型或委托类型。
reference-type:
class-type
interface-type
array-type
delegate-type
class-type:
object
string
interface-type:
array-type:
non-array-typerank-specifiers
non-array-type:
type
rank-specifiers:
rank-specifier
rank-specifiersrank-specifier
rank-specifier:
[dim-separatorsopt]
dim-separators:
dim-separators,
delegate-type:
引用类型值是对该类型的某个实例(instance)的一个引用,后者称为对象(object)。
null值比较特别,它兼容于所有引用类型,用来表示“没有被引用的实例”。
1.2.1类类型
类类型定义包含数据成员、函数成员和嵌套类型的数据结构,其中数据成员包括常量和字段,函数成员包括方法、属性、事件、索引器、运算符、实例构造函数、析构函数和静态构造函数。
类类型支持继承,继承是派生类可用来扩展和专门化基类的一种机制。
类类型的实例是用object-creation-expressions(第7.5.10.1节)创建的。
有关类类型的介绍详见第10节。
某些预定义类类型在C#语言中有特殊含义,如下表所示。
类类型
说明
System.Object
所有其他类型的最终基类。
请参见第4.2.2节。
System.String
C#语言的字符串类型。
请参见第4.2.3节。
System.ValueType
所有值类型的基类。
请参见第4.1.1节。
System.Enum
所有枚举类型的基类。
请参见第14节。
System.Array
所有数组类型的基类。
请参见第12节。
System.Delegate
所有委托类型的基类。
请参见第15节。
System.Exception
所有异常类型的基类。
请参见第16节。
1.2.2对象类型
object类类型是所有其他类型的最终基类。
C#中的每种类型都是直接或间接从object类类型派生的。
关键字object只是预定义类System.Object的别名。
1.2.3string类型
string类型是直接从object继承的密封类类型。
string类的实例表示Unicode字符串。
string类型的值可以写为字符串(第2.4.4节)。
关键字string只是预定义类System.String的别名。
1.2.4接口类型
一个接口定义一个协定。
实现某接口的类或结构必须遵守该接口定义的协定。
一个接口可以从多个基接口继承,而一个类或结构可以实现多个接口。
有关接口类型的介绍详见第13节。
1.2.5数组类型
数组是一种数据结构,它包含可通过计算索引访问的零个或更多个变量。
数组中包含的变量(又称数组的元素)具有相同的类型,该类型称为数组的元素类型。
有关数组类型的介绍详见第12节。
1.2.6委托类型
委托是一种数据结构,它引用一个或多个方法,对于实例方法,还引用这些方法所对应的对象实例。
在C或C++中与委托最接近的是函数指针,但函数指针只能引用静态函数,而委托则既可以引用静态方法,也可以引用实例方法。
在后一种情况中,委托不仅存储了一个对该方法入口点的引用,还存储了一个对相应的对象实例的引用,该方法就是通过此对象实例被调用的。
有关委托类型的介绍详见第15节。
1.3装箱和拆箱
装箱和拆箱的概念是C#的类型系统的核心。
它在value-type和reference-type之间的架起了一座桥梁,使得任何value-type的值都可以转换为object类型的值,反过来转换也可以。
装箱和拆箱使我们能够统一地来考察类型系统,其中任何类型的值最终都可以按对象处理。
1.3.1装箱转换
装箱转换允许将value-type隐式转换为reference-type。
存在下列装箱转换:
∙从任何value-type(包括任何enum-type)到类型object。
∙从任何value-type(包括任何enum-type)到类型System.ValueType。
∙从任何value-type到value-type实现的任何interface-type。
∙从任何enum-type到System.Enum类型。
将value-type的一个值装箱包括以下操作:
分配一个对象实例,然后将value-type的值复制到该实例中。
最能说明value-type的值的实际装箱过程的办法是,设想有一个为该类型设置的装箱类(boxingclass)。
对任何value-type的T而言,装箱类的行为可用下列声明来描述:
sealedclassT_Box:
System.ValueType
Tvalue;
publicT_Box(Tt){
value=t;
T类型值v的装箱过程现在包括执行表达式newT_Box(v)和将结果实例作为object类型的值返回。
因此,下面的语句
inti=123;
objectbox=i;
在概念上相当于
objectbox=newint_Box(i);
实际上,像上面这样的T_Box和int_Box并不存在,并且装了箱的值的动态类型也不会真的属于一个类类型。
相反,T类型的装了箱的值属于动态类型T,若用is运算符来检查动态类型,也仅能引用类型T。
例如,
if(boxisint){
Console.Write("
Boxcontainsanint"
);
将在控制台上输出字符串“Boxcontainsanint”。
装箱转换隐含着复制一份待装箱的值。
这不同于从r