C#专题之C#的类型与变量

思多雅[天行健] 发布时间:2008.11.09
    在前面的几个章节中,我们学习了C#的基本概念,这一章,我们来学习C#的类型与变量。
    C#语言的类型被分为三类:数值类型、引用类型和指针类型。
       type:
           value-type
           reference-type
           poin ter-typ e
    注意:指针类型只能用在不安全代码,我们在后面的章节中会进行专门的讨论。
    数值类型与引用类型所不同的是,数值类型变量直接含有它们的数据,然而引用类型的变量存储对它们的数据的引用,就是后面要介绍的对象。对于引用类型,可能会出现两个变量引用相同对象的情况,这样对于一个变量的的操作就有可能影响到由其它变量引用的对象。对于数值类型,每个变量都有它们自己对数据的拷贝,这样就不可能出现一个对变量的操作影响到另外一个的情况。
    C#的类型系统是统一的,这样任何类型的数据都可以被看做对象。C#中的任何类型都直接或间接地从objiect 类类型派生,而object 是所有类型的最基本类类。引用类型的数值被看做通过对象,这些对象通过把数值看做类型对象来简化。数值类型的数值通过包装和解包操作来被当做对象。

-------思多雅[天行健]版权所有,首发太平洋论论坛,转载请注明-------

一、C#的数值类型
    数值类型既是一个结构类型也是枚举类型。C#提供了一系列预定义结构类型,称为简单类型。简单类型通过保留字指定,并且进一步分成数字类型,整数类型和浮点数类型。
       value-type :
           struct-typ e
           enum-type
       struct-typ e:
           type-name
           simp le-type
       simp le-type :
           numeric-type
           bool
       numeric-type :
           integral-type
           floa ting-point-type
           decimal
       integral-type :
           sbyte
           byte
           short
           ushort
           int
           uint
           long
           ulong
           char
      floa ting-point-type:
         float
         double
      enum-type :
         type-name
    所有数值类型都隐式地从类object 继承。不允许任何类型从数值类型派生,因而数值类型是被默认封闭的。
    一个数值类型的变量通常包含一个那种类型的数值。不像引用类型,数值类型的数值不能为null 或是引用一个进一步派生类型的变量。
    对某个数值类型的变量赋值就会创建一个对所赋数值的拷贝,它复制了引用而不是引用所指定的对象。

1.1 默认构造函数
    所有类型都隐含地声明了一个公共的无参数的构造函数,称为默认构造函数。默认构造函数返回一个初始值为零的实例,为数值类型的默认数值:
  对于所有单独类型,默认数值是由一个零位格式产生的数值:
  对于sbyte、byte、short、ushort、int、uint、long和ulong,默认的数值为0。
  对于char,默认的数值为'\x0000'。
  对于float,默认的数值是0.0f。
  对于double,默认的数值为0.0d。
  对于decimal,默认的数值为0.0m。
  对于bool,默认的数值为false。
  对于一个枚举类型E,默认数值是0。
  对于结构类型,默认数值是把所有数值类型域设为它们的默认类型并且把所有引用类型域设为null的数值。
    像其它任何构造函数一样,一个数值类型的默认的构造函数用new 操作符调用。在下面的例子中,变量i 和j 都初始化为0。
      class A
      {
         void F() {
            int i = 0;
            int j = new int();
          }
      }
    如上所示,因为每个数值类型隐含的都有公共无参数构造函数,所以让一个结构类型包含一个外部声明的无参数构造函数是不可能的。一个结构类型可以允许声明一个参数化的构造函数。例如
      struct Point
      {
         int x, y;
public Point(int x, int y) {
             this.x = x;
             this.y = y;
           }
       }
    如果已经给出上面的声明,那么语句
       Point p1 = new Point();
       Point p2 = new Point(0, 0);
    都会创建一个Point,其中x 和y 被初始化为0。

1.2 结构类型
    一个结构类型是一个数值类型,它可以声明构造函数、常数、域、方法、属性、索引、操作符和嵌套类型。结构类型在第11章中描述。

1.3 简单类型
    C#提供了一系列的预定义结构类型,称为简单类型。这些简单类型通过关键词确定,但是这些关键词可以为在System 名称空间中的预定义结构类型关键词起简单的别名,就像下面表中所示。
   关键字                有别名的类型
   sbyte              System.SByte
   byte               System.Byte
   short              System.Int16
   ushort             System.Uint16
   int                System.Int32
   uint               System.Uint32
   long               System.Int64
   ulong              System.Uint64
   char               System.Char
   float              System.Single
   double             System.Double
   bool               System.Boolean
   decimal            System.Decimal
    一个简单类型和它有别名的结构类型是不可分辨的。换句话说,当写下保留字byte 时和写System.Byte确实没有什么区别,并且用System.Int32 也与用保留字int 相同。
    因为一个简单类型代表了一个结构类型,所以每个简单类型都有成员。例如,int 有在System.Int32 中声明的成员和从System.Object 中继承的成员,并且下面的语句是允许的:
      int i = int.MaxValue;           // System.Int32.MaxValue constant
      string s = i.ToString();        // System.Int32.ToString() instance method
      string t = 123.ToString();      // System.Int32.ToString() instance method
    注意,整数文字上是int 类型数据,并且同时也是System.Int32 结构类型的数据。
简单类型与其它结构类型,其它结构类型允许包含附加操作符:
  大多数简单类型允许通过使用文字来创建 (§错误!未找到引用源。)。例如,123 是int 类型量,而'a'是字符类型量。C#使得不用对其它结构类型文字进行预定义,而其它结构类型数据基本上是通过那些结构类型的构造函数来创建。
  当一个表达式的运算符都是简单类型常数时,编译器在编译时就可以对这个表达式进行赋值。这样一个表达式称为常数表达式(§错误!未找到引用源。)。包括其它结构类型定义的操作符的表达式通常意味着运行时赋值。
  通过const 声明,就有可能声明一个简单类型(§10.3)的常数。不可能有其它结构类型的常数,但是static readonly 域提供了相似的作用。
  包括简单类型的转换可以参加由其它结构类型定义的转换操作符的赋值,但是用户定义的转换操作符不能参与另外一个用户定义操作符的赋值。

1.4 整数类型
    C#支持九种整数类型: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 到18446744073709551615。
  char类型表示无符号16位整数,数值范围为0 到65535。char类型的可能数值集符合Unicode字符集。
整数类型一元和二元操作符总是按有符号32 位精度、无符号32 位精度、有符号64 位精度或无符号64位精度进行操作。
  对于一元+和~操作符,操作数被转换为类型T,这里T 是int、uint、long 和ulong 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T。
  对于一元操作符-,操作数被转换为类型T,这里T 是int 和long 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T。一元操作符-不能应用于ulong 类型操作数。
  对于二元操作符+、–、*、/、%、&、^、|、==、!=、>、<、>=和<=操作符,操作数被转换为类型T,这里T 是int、uint、long 和ulong 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T (或相关操作符bool )。
  对于二元操作符<<和>>操作符,操作数被转换为类型T,这里T 是int、uint、long 和ulong 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T

char 类型被分类为一种整数类型,但是它在两点上不同于其它整数类型:
  没有从其它类型到字符类型的隐含的转换。甚至,即使sbyte、byte和ushort类型的数据完全可以用char类型代表,但是从sbyte、byte和ushort类型到char 的隐含转换也不存在。
*  char 类型的常数必须写成字符文字。字符常量可以只是写成与一个斜杠结合的整数文字。例如,(char)10与'\x000A'相同。
    checked和unchecked操作符和语句用来控制检查整数类型算术操作和转换(§7.5.13)的溢出。在一段checked上下文中,一个溢出产生一个编译时错误或者引起扔出一个OverflowException。在一段unchecked 的上下文里,溢出被忽略并且不需要送到目标类型的任何高端位被丢弃。

1.5 浮点类型
C#支持两个浮点类型:float和double。float和double类型用32位单精度和64位双精度IEEE754格式来表示,它提供了一系列数值:
  正零和负零。在大多数情况下,正零和负零与简单的零值相同,但是它们的使用中间有一些区别。
  正无穷大和负无穷大。无穷大是由一个非零成员除以零的操作产生的。例如,1.0/0.0产生正无穷大,而–1.0/0.0产生负无穷大。
  非数字数据,通常缩写为NaN 。NaN 是无效的浮点数操作产生的,例如零除以零。
  形如s × m × 2e  的非零数据有限集,这里s 是1 或者-1,而m 和e 由具体浮点数类型决定:对于float,0 < m < 224  和-149 ≤e ≤ 104,对于double,0 < m < 253  和-1075 ≤e ≤ 970。
float 类型可以代表的数值范围大约从1.5 × 10-45  到3.4 × 1038 ,有7 位数字位精度。
double类型可以代表的数值范围大约从5.0 × 10-324  到1.7 × 10308 ,有15 到16位数字位精度。
如果二元运算符的一个操作数是浮点类型,那么其它操作数必须是整数类型或者是浮点数类型,并且操作按下面求值:
  如果一个操作数是整数类型,那么那个操作数会被转换为与其它操作数一样的浮点数类型。
  如果操作数是double 类型,其它操作数就要转换为double,操作就要按照double 类型的范围和精度来进行,而且计算的结果也是double 类型(对于相关操作,或者是bool)。
  否则,操作至少使用float 的范围和精度,而且计算的结果也是float 类型 (对于相关操作,或者是(bool )。
   
    包括赋值操作符的浮点操作符,从不产生异常。在异常情况下,浮点数操作会产生下面介绍的零、无穷大或NaN 作为替代:
  如果浮点数操作的结果对于目标形式来说太小,操作的结果就会转换为正零或负零。
  如果浮点数操作的结果对于目标形式来说太大,操作的结果就会转换为正无穷大或负无穷大。
  如果浮点数的操作是无效的,操作的结果就会转换为NaN 。
  如果一个或所有浮点操作的操作数都是NaN,那么操作的结果就变为NaN 。
    浮点数操作可以用比操作结果的类型更高的精度来执行。例如,一些硬件结构支持一个比double 类型更大范围和更高精度的“扩展的”或“long double”浮点数类型,并且会隐含地使用这个更高的精度来实现浮点数操作。只有在性能要额外付出时,这样的硬件结构才会被用来实现精度小一些的浮点数操作,而不需要执行同时丧失性能和精度,C#允许所有的浮点数操作使用更高的精度类型。与给出更高精度的结果不同,这样几乎没有任何可测量的影响。在形如x *y/ z 的表达式中,这里的乘法产生一个超出double 类型范围的结果,但是后面的除法带来一个回到double 范围的暂时结果,实际上在大一些的范围形式计算这个表达式会产生有限的结果而不是无穷大。

1.6 十进制类型
    十进制类型是一个128位数据类型,适合金融和货币计算。十进制类型可以代表的数值范围是从      -28          28
1.0 × 10 到大约7.9 × 10 ,有28 到29 个有效数字位。 e ,这里s 是1 或者-1,0 ≤m < 296 而-28 ≤e ≤ 0 。
十进制
十进制类型数值的有限集合形式为s × m × 10
类型不支持有符号零、无穷大和NaN 。
    一个十进制数由96 位整数和十位幂表示。对于一个绝对数值小于1.0m 的十进制数,数据就是第28 个十进制位,但是没有更多。对于绝对值大于或等于1.0m 的十进制数,数据可能是28 或29 数字位。与float 和double 类型相比,如0.1 的十进制小数成员可以就用十进制表示。在用float 和double 表示时,这样的成员经常为无穷小数,使得这些表示有更大的舍入误差。
     如果一个二元操作符的操作数是十进制类型,其它操作数也必须是整数类型或十进制类型。如果要使用一个整数类型操作数,在操作被执行前它会被转换为十进制数。
    十进制类型的数值的操作就是28 或29 数字位,但是不会多于28 十进制位。结果为最接近的可表示的数值,当结果与两个可表示数值都距离都相等时,选择在最小数据位上为奇数的数值。
    如果十进制算术操作产生了一个在舍入后对于十进制形式太小的数据,操作的结果就变为零。如果一个十进制算术操作产生了一个对于十进制形式太大的数据,就会抛出一个OverflowException错误。
    十进制类型比浮点类型有更高的精度但是有更小的范围。这样,从浮点数类型转换到十进制类型也许会产生溢出的异常,并且从十进制类型转换到浮点数类型也许会有精度损失。出于这些原因,不存在浮点数类型和十进制类型间的隐式转换,并且也没有显式的情况,在同一个表达式中把浮点数和十进制操作数混合在一起是不可能的。

1.7 布尔类型
    bool类型表示布尔逻辑量,bool类型的可能值为true和false。
    在bool 和其它类型间不存在标准的转换。特别是,bool 类型与整数类型截然不同,bool 数据不能用于使用整数类型的地方,反之亦然。
    在C 和C++语言中,零整数值或空指针可以被转换为布尔数值false,而非零整数数值或非空指针可以转换为布尔数值true 。但在C#中,这样的转换由显式地把整数数值和零比较或显式地把对象和null 比较来实现。

4.1.8 枚举类型
枚举类型是一种有名称常数的独特类型。每个枚举类型都有前级类型,可以是byte、short、int或long。枚举类型通过枚举声明来定义。

-------思多雅[天行健]版权所有,首发太平洋论论坛,转载请注明-------

小结,大家要多注意一下C#与C++及C语言中指针及类型的对比。有时不小心,就会引起出错,在检查时,留意查查这方面就是了。

你可能感兴趣的:(C#专题之C#的类型与变量)