<展现C#>第四章C#类型

<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
document.write(baiduCproIFrame());-->
                                  第四章  C# 类型

    既然你知道了怎样创建一个简单的C#程序,我将会给你介绍C#的 类型系统。在这一章中,你学到如何使用不同的值和引用 类型,加框和消框机制能为你作些什么。尽管这一章的不侧重于例子,但你可以学到很多重要的信息,关于如何创建现成 类型的程序。
4.1值 类型
    各种值 类型总是含有相应该 类型的一个值。C#迫使你初始化变量才能使用它们进行计算-变量没有初始化不会出问题,因为当你企图使用它们时,编译器会告诉你。    
每当把一个值赋给一个值 类型时,该值实际上被拷贝了。相比,对于引用 类型,仅是引用被拷贝了,而实际的值仍然保留在相同的内存位置,但现在有两个对象指向了它(引用它)。C#的值类
型可以归类如下:
·简单 类型(Simpletypes)
·结构 类型(structtypes)
·枚举 类型(Enumerationtypes)
4.1.1  简单 类型
    在C#中出现的简单 类型共享一些特性。第一,它们都是.NET系统 类型的别名。第二,由简单 类型组成的常量表达式仅
在编译时而不是运行时受检测。最后,简单 类型可以按字面被初始化。以下为C#简单 类型归类:
·整型
·布尔型
·字符型(整型的一种特殊情况)
·浮点型
·小数型

4.1.1.1  整型
    C#中有9个整型。sbyte、byte、short、ushort、int、uint、long、ulong和char(单独一节讨论)。它们
具有以下特性:

·sbyte型为有符号8位整数,取值范围在128~127之间。     
·bytet型为无符号16位整数,取值范围在0~255之间。
·short型为有符号16位整数,取值范围在-32,768~32,767之间。
·ushort型为无符号16位整数,取值范围在0~65,535之间。
·int型为有符号32位整数,取值范围在-2,147,483,648~2,147,483,647之间。
·uint型为无符号32位整数,取值范围在  0~4,294,967,295之间。
·long型为64位有符号整数,取值范围在9,223,372,036,854,775,808~9,223,372,036,854,775,807之间。
·ulong型为64位无符号整数,取值范围在0~18,446,744,073,709,551,615之间。

    VB和C程序员都可能会对int和long数据 类型所代表的新范围感到惊讶。和其它的编程语言相比,在C#中,int不再取决
于一个机器的字(word)的大小,而long被设成64位。

4.1.1.2  布尔型
    布尔数据 类型有true和false两个布尔值。可以赋于true或false值给一个布尔变量,或可以赋于一个表达式,其所求
出的值等于两者之一:
boolbTest=(80& gt;90);
         与C和C++相比,在C#中,true值不再为任何非零值。不要为了增加方便而把其它整型转换成布尔型。

4.1.1.3  字符型
    字符型为一个单Unicode字符。一个Unicode字符16位长,它可以用来表示世界上多种语言。可以按以下方法给一个字
符变量赋值:
charchSomeChar='A';
     除此之外,可以通过十六进制转义符(前缀/x)或Unicode表示法给变量赋值(前缀/u):
charchSomeChar='/x0065';
charchSomeChar='/u0065';
    不存在把char转换成其它数据 类型的隐式转换。这就意味着,在C#中把一个字符变量当作另外的整数数据 类型看待是
行不通的——这是C程序员必须改变习惯的另一个方面。但是,可以运用显式转换:
charchSomeChar=(char)65;
intnSomeInt=(int)'A';
      在C中仍然存在着转义符(字符含义)。要换换脑筋,请看表4.1。

Table4.1转义符(EscapeSequences)

转义符                  字符名
/'                            单引号
/"                           双引号
//                           反斜杠
/0                        空字符
/a                        感叹号(Alert  )
/b                        退格
/f                        换页
/n                       新行
/r                        回车
/t                       水平tab
/v                      垂直tab

4.1.1.4  浮点型
     两种数据 类型被当作浮点型:float和double。它们的差别在于取值范围和精度:
     float:取值范围在1.5x10^-45~3.4x10^38之间,精度为7位数。
     double:取值范围在5.0x10^-324~1.7x10^308之间,精度为15~16位数。
    当用两种浮点型执行运算时,可以产生以下的值:
    正零和负零
    正无穷和负无穷
    非数字值(Not-a-Number,缩写NaN)
    非零值的有限数集
    另一个运算规则为,当表达式中的一个值是浮点型时,所有其它的 类型都要被转换成浮点型才能执行运算。

4.1.1.5   小数型(Thedecima ltype)
    小数型是一种高精度、128位数据 类型,它打算用于金融和货币的计算。它所表示的范围从大约1.0x10^-28到
7.9x10^28,具有28至29位有效数字。要注意,精度是以位数(digits)而不是以小数位(decimalplaces)表示。运算准确
到28个小数位的最大值。
    正如你所看到的,它的取值范围比double的还窄,但它更精确。因此,没有decimal和double之间的隐式转换——往一
个方向转换可能会溢出,往另外一个方向可能会丢失精度。你不得不运用显式转换。
     当定义一个变量并赋值给它时,使用m后缀以表明它是一个小数型:
          decimaldecMyValue=1.0m;
     如果省略了m,在变量被赋值之前,它将被编译器认作double型。

4.1.2  结构 类型
     一个结构 类型可以声明构造函数、常数、字段、方法、属性、索引、操作符和嵌套 类型。尽管列出来的功能看起来象
一个成熟的类,但在C#中,结构和类的区别在于结构是一个值 类型,而类是一个引用 类型。与C++相比,这里可以用结构关
键字定义一个类。
    使用结构的主要思想是用于创建小型的对象,如Point和FileInfo等等。你可以节省内存,因为没有如类对象所需的那
样有额外的引用产生。例如,当声明含有成千上万个对象的数组时,这会引起极大的差异。
    清单4.1  包含一个命名为IP的简单结构,它表示一个使用byte 类型的4个字段的IP地址。我不包括方法等,因为这些
工作正如使用类一样,将在下一章有详细的描述。

清单4.1   定义一个简单的结构

1:usingSystem;
2:
3:structIP
4:{
5:  publicbyteb1,b2,b3,b4;
6:}
7:
8:classTest
9:{
10:  publicstaticvoidMain()
11:  {
12:   IPmyIP;
13:   myIP.b1=192;
14:   myIP.b2=168;
15:   myIP.b3=1;
16:   myIP.b4=101;
17:   Console.Write("{0}.{1}.",myIP.b1,myIP.b2);
18:   Console.Write("{0}.{1}",myIP.b3,myIP.b4);
19:  }
20:}

4.1.3  枚举 类型
   当你想声明一个由一指定常量集合组成的独特 类型时,枚举 类型正是你要寻觅的。最简单的形式,它看起来可能象这
样:
        enumMonthNames{January,February,March,April};
   因我惯用缺省设置,故枚举元素是int型,且第一个元素为0值。每一个连续的元素按1递增。如果你想给第一个元素直
接赋值,可以如下把它设成1:
        enumMonthNames{January=1,February,March,April};
    如果你想赋任意值给每个元素——甚至相同的值——这也没有问题:
        enumMonthNames{January=31,February=28,March=31,April=30};
    最后的选择是不同于int的数据 类型。可以在一条语句中按如此赋值:
         enumMonthNames:byte{January=31,February=28,March=31,April=30};
    你可以使用的 类型仅限于long、int、short和byte。


4.2   引用 类型
    和值 类型相比,引用 类型不存储它们所代表的实际数据,但它们存储实际数据的引用。在C#中提供以下引用 类型给你
使用:
·对象 类型
·类 类型
·接口
·代表元
·字符串 类型
·数组

4.2.1  对象 类型
    对象 类型是所有 类型之母——它是其它 类型最根本的基类。因为它是所有对象的基类,所以可把任何 类型的值赋给
它。例如,一个整型:
         objecttheObj=123;
    给所有的C++程序员一个警告:object并不等价于你可能正在寻找的void*。无论如何,忘掉指针总是个好主意。
    当一个值 类型被加框(作为一个对象利用)时,对象 类型就被使用了。这一章稍后会讨论到加框和消框

4.2.2   类 类型
    一个类 类型可以包含数据成员、函数成员和嵌套 类型。数据成员是常量、字段和事件。函数成员包括方法、属性、索
引、操作符、构造函数和析构函数。类和结构的功能是非常相似的,但正如前面所述,结构是值 类型而类是引用 类型
    和C++相比,仅允许单继承。(你不能拥有派生一个新对象的多重基类。)  但是,C#中的一个类可以派生自多重接
口,该接口在下一节将得到描述。
    第五章“类”专门讨论使用类编程。这一节仅打算给出C#类在哪里适合 类型图的一个全貌。

4.2.3  接口
     一个接口声明一个只有抽象成员的引用 类型。跟C++中相似的概念为:一个结构的成员,且方法等于0。如果你不知道
那些概念的任何东西,这里就是在C#中一个接口实际所做的。仅仅只存在着方法标志,但根本就没有执行代码。这就暗示
了不能实例化一个接口,只能实例化一个派生自该接口的对象。
     可以在一个接口中定义方法、属性和索引。所以,对比一个类,接口有什么特殊性呢?当定义一个类时,可以派生自
多重接口,而你只能可以从仅有的一个类派生。
     你可能会问:"OK,但我必须实现所有的接口成员,那么我能从这个途径得到什么呢?"我想举一个来自.NET的例子:
很多类实现了IDictionary接口。你可以使用简单的 类型转换访问接口:
IDictionarymyDict=(IDictionary)someobjectthatsupportsit;
     现在你的代码可以访问字典了。可等等,我说很多类可以实现这个接口——所以,你可以在多个地方重用代码来访问
IDictionary接口!一旦学会,任何地方都可使用。
     当你决定在类设计中使用接口时,学习更多关于面向对象的设计是个好主意。这本书不能教你这些概念,但你可以学
习如何创建接口。以下的代码段定义接口IFace,它只有一个方法:
interfaceIFace
{
voidShowMyFace();
}
     正如我所提到的,不能从这个定义实例化一个对象,但可以从它派生一个类。因此,该类必须实现ShowMyFace抽象方
法:
classCFace:IFace
{
publicvoidShowMyFace()
{
  Console.WriteLine("implementation");
}
}

   接口成员和类成员的区别在于,接口成员不能被实现。因此,我不想在下一章中再次提到这一点。

4.2.4  代表元
    一个代表元封装了具有一些标志的一个方法。基本上,代表元是 类型安全和函数指针的安全版本(回调功能)。可以同
时在一个代表元实例中同时封装静态和实例方法。
尽管你可以用代表员当作具有方法,但它们的主要用途是拥有有一个类事件。再次,我想把你引到下一章,那里会详细地
讨论类。
4.2.5  字符串 类型
   C程序员可能会诧异,但当然,C#有一个用于操作字符串数据的基本字符串 类型。字符串类直接派生自对象,且它是被
密封的,这意味着再不能从它派生类。就象其它 类型,字符串是预定义类SystemString的一个别名。
   它的用法十分简单:
stringmyString="sometext";
   合并字符串同样简单:
stringmyString="sometext"+"andabitmore";
   而如果你想访问单个字符,所要做的就是访问下标:
charchFirst=myString[0];
当比较两个字符串是否相等时,简单地使用"=="比较操作符。
if(myString==yourString)...
我只不过想提到,尽管字符串是一个引用 类型,比较时是比较值,而不是比较引用(内存地址)。
   字符串 类型几乎用于这本书的每一个例子中,而且在这些例程中,我会介绍给你一些由字符串对象所显露的极其有趣的
方法。
4.2.6  数组
     一个数组包含有通过计算下标访问的变量。所有包含于数组中且被当作元素的变量必须是同一 类型。这种 类型自然被
称为"数组 类型"。数组可以存储整数对象、字符串对象或者你提出的任何对象。
      数组的维数就是所谓的排(rank),它决定了相关数组元素的下标数。最常用的数组是一维数组(第一排)。一个多维
数组具有的排数大于1。每个维的下标始于0,终于维的长度减1。
应有足够的理论支持。让我们看一下用一个数组初始化器(arrayinitializer)初始化的数组:
string[]arrLanguages={"C","C++","C#"};
     该简写效果等同以下:
arrLanguages[0]="C";arrLanguages[1]="C++";arrLanguages[2]="C#";
     而编译器为你做了所有的工作。当然,它将同样为多维数组初始化器工作:
int[,]arr={{0,1},{2,3},{4,5}};
     它是以下的简写:
arr[0,0]=0;arr[0,1]=1;
arr[1,0]=2;arr[1,1]=3;
        arr[2,0]=4;arr[2,1]=5;
    如果你不想事先初始化一个数组,但知道了它的大小,该声明就象这样:
        int[,]myArr=newint[5,3];
    如果数组的大小必须动态地被计算,用于数组创建的语句可以象这样写:
        intnVar=5;
        int[]arrToo=newint[nVar];
    正如我在这一节开始所陈述的,你可以往数组里面塞任何东西,只要所有的元素 类型都相同。因此,如果你想把任何
东西放进一个数组,就声明它的 类型为对象:

4.3  加框和消框
      这一章的课程中,我已经给出了各式各样的值 类型和引用 类型。由于速度的原因,你会使用值 类型——它除了占据
一定空间的内存块外,就没有什么了。但是,有时对象的方便性就象值 类型一样好用。
      这就是加框和消框登上了舞台的地方,加框和消框是C# 类型系统的核心概念。通过允许一个值 类型转换成 类型对象
或从 类型对象转换成值 类型,这种机制形成了值 类型和引用 类型之间的捆绑连接。任何东西终究是一个对象——但是,仅
当需要它们是对象时。
4.3.1  加框转换
     给一个值加框指隐式地把任何值 类型转换成 类型对象。当一个值 类型被加框时,一个对象实例就被分配,且值 类型
值被拷贝给新的对象。
看以下例子:
        intnFunny=2000;
        objectoFunny=nFunny;
     第二行的赋值暗示调用一个加框操作。nFunny整型变量的值被拷贝给oFunny对象。现在整型变量和对象变量都同时存
在于栈中,但对象的值居留在堆中。
      那么,它暗示着什么呢?它们的值互相独立——在它们之间没有连接。(oFunny没有引用nFunny的值。)  以下代码说
明了结果:
        intnFunny=2000;
        objectoFunny=nFunny;
        oFunny=2001;
        Console.WriteLine("{0}{1}",nFunny,oFunny);
     当代码改变oFunny的值时,nFunny的值并没有改变。只要你脑袋中有这个copy动作,就能够使用值 类型的对象功能,
发挥出你的巨大优势!
4.3.2  消框转换
    和加框相比,消框是显式操作——必须告诉编译器,你想从对象中抽取出哪一种值 类型。当执行消框操作时,C#检测
所请求的值 类型实际上存储在对象实例中。经过成功的校验,该值被消框。

    这就是消框如何执行:
intnFunny=2000;
objectoFunny=nFunny;
intnNotSoFunny=(int)oFunny;

    如果错误地请求一个double值
doublenNotSoFunny=(double)oFunny;
通用语言运行时(CommonLanguageRuntime,简写CLR)将会引发一个InvalidCastException异常。你可以在第7章"异常处
理"中学到更多有关异常处理的知识。

4.4  小结
    在这一章中,你学到了C#中用到的各种 类型。简单的值 类型包括整型、布尔型、浮点型和小数型。你会非常经常地用
到一些 类型,进行数学和金融的计算,还有逻辑表达。
在介绍引用 类型之前,我显示了一个看起来象类的结构 类型。它几乎如一个类般地运作,但它只是一个值 类型,这使它更
加适合需要有大量的小对象的场合。
    引用 类型起始于所有对象之母的objedt本身。object是C#中所有对象的基类,且它同样用于值 类型的加框和消框。除
此之外,我还让你领略了代表元、字符串和数组。
    令C#程序员十分神气的 类型就是类。它是C#面向对象编程的心脏,下一章整章专门让你迅速理解这个激动人心且功能
强大的 类型
<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值