c#

位置:IT落伍者 >> c# >> 浏览文章

展现C#世界之四:C#类型


发布日期:2022年05月02日
 
展现C#世界之四:C#类型

第四章 C#类型

既然你知道了怎样创建一个简单的C#程序我将会给你介绍C#的类型系统在这一章中你学到如何使用不同的值和引用类型加框和消框机制能为你作些什么尽管这一章的不侧重于例子但你可以学到很多重要的信息关于如何创建现成类型的程序

值类型

各种值类型总是含有相应该类型的一个值C#迫使你初始化变量才能使用它们进行计算变量没有初始化不会出问题因为当你企图使用它们时编译器会告诉你 每当把一个值赋给一个值类型时该值实际上被拷贝了相比对于引用类型仅是引用被拷贝了而实际的值仍然保留在相同的内存位置但现在有两个对象指向了它(引用它)C#的值类型可以归类如下

简单类型(Simple types )

结构类型(struct types)

枚举类型(Enumeration types)

简单类型

在C#中出现的简单类型共享一些特性第一它们都是NET系统类型的别名第二由简单类型组成的常量表达式仅在编译时而不是运行时受检测最后简单类型可以按字面被初始化以下为C#简单类型归类

整型

布尔型

字符型 (整型的一种特殊情况)

浮点型

小数型

整型

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

sbyte型为有符号位整数取值范围在~之间

bytet型为无符号位整数取值范围在~之间

short型为有符号位整数取值范围在~之间

ushort型为无符号位整数取值范围在~之间

int型为有符号位整数取值范围在~ 之间

uint型为无符号位整数取值范围在 ~ 之间

long型为位有符号整数取值范围在~ 之间

ulong型为位无符号整数取值范围在 ~ 之间

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

布尔型

布尔数据类型有true和false两个布尔值可以赋于true或false值给一个布尔变量或可以赋于一个表达式其所求出的值等于两者之一

bool bTest = ( >

与C和C++相比在C#中true值不再为任何非零值不要为了增加方便而把其它整型转换成布尔型

字符型

字符型为一个单Unicode 字符一个Unicode字符位长它可以用来表示世界上多种语言可以按以下方法给一个字符变量赋值

char chSomeChar = A

除此之外可以通过十六进制转义符(前缀\x)或Unicode表示法给变量赋值(前缀\u)

char chSomeChar = \x

char chSomeChar = \u

不存在把char转换成其它数据类型的隐式转换这就意味着在C#中把一个字符变量当作另外的整数数据类型看待是行不通的——这是C程序员必须改变习惯的另一个方面但是可以运用显式转换

char chSomeChar = (char)

int nSomeInt = (int)A

在C中仍然存在着转义符(字符含义)要换换脑筋请看表

table 转义符( Escape Sequences)

转义符 字符名

\ 单引号

\ 双引号

\\ 反斜槓

\ 空字符

\a 感歎号(Alert )

\b 退格

\f 换页

\n 新行

\r 回车

\t 水平 tab

\v 垂直tab

浮点型

两种数据类型被当作浮点型float和double它们的差别在于取值范围和精度

float 取值范围在 x^~ x^之间 精度为位数

double 取值范围在 x^ ~ x^之间 精度为 ~ 位数

当用两种浮点型执行运算时可以产生以下的值

正零和负零

正无穷和负无穷

非数字值(NotaNumber缩写NaN)

非零值的有限数集

另一个运算规则为当表达式中的一个值是浮点型时所有其它的类型都要被转换成浮点型才能执行运算

小数型(The decimal Type)

小数型是一种高精度位数据类型它打算用于金融和货币的计算它所表示的范围从大约x^x^具有位有效数字要注意精度是以位数 (digits)而不是以小数位(decimal places)表示运算准确到个小数位的最大值

正如你所看到的它的取值范围比double的还窄但它更精确因此没有decimal和double之间的隐式转换——往一个方向转换可能会溢出往另外一个方向可能会丢失精度你不得不运用显式转换

当定义一个变量并赋值给它时使用 m 后缀以表明它是一个小数型

decimal decMyValue = m

如果省略了m在变量被赋值之前它将被编译器认作double型

结构类型

一个结构类型可以声明构造函数常数字段方法属性索引操作符和嵌套类型尽管列出来的功能看起来象一个成熟的类但在C#中结构和类的区别在于结构是一个值类型而类是一个引用类型与C++相比这里可以用结构关键字定义一个类

使用结构的主要思想是用于创建小型的对象如Point和FileInfo等等你可以节省内存因为没有如类对象所需的那样有额外的引用产生例如当声明含有成千上万个对象的数组时这会引起极大的差异

清单 包含一个命名为IP的简单结构它表示一个使用byte类型的个字段的IP地址我不包括方法等因为这些工作正如使用类一样将在下一章有详细的描述

清单 定义一个简单的结构

using System

struct IP

{

public byte bbbb

}

class Test

{

public static void Main()

{

IP myIP

myIPb =

myIPb =

myIPb =

myIPb =

ConsoleWrite({}{}myIPbmyIPb

ConsoleWrite({}{}myIPbmyIPb

}

}

枚举类型

当你想声明一个由一指定常量集合组成的独特类型时枚举类型正是你要寻觅的最简单的形式它看起来可能象这样

enum MonthNames { January February March April }

因我惯用缺省设置故枚举元素是int型且第一个元素为每一个连续的元素按递增如果你想给第一个元素直接赋值可以如下把它设成

enum MonthNames { January= February March April }

如果你想赋任意值给每个元素——甚至相同的值——这也没有问题

enum MonthNames { January= February= March= April= }

最后的选择是不同于int的数据类型可以在一条语句中按如此赋值

enum MonthNames byte { January= February= March= April= }

你可以使用的类型仅限于longintshort和byte

引用类型

和值类型相比引用类型不存储它们所代表的实际数据但它们存储实际数据的引用在C#中提供以下引用类型给你使用

对象类型

类类 型

接口

代表元

字符串类型

数组

对象类型

对象类型是所有类型之母——它是其它类型最根本的基类因为它是所有对象的基类所以可把任何类型的值赋给它例如一个整型

object theObj =

给所有的C++程序员一个警告object并不等价于你可能正在寻找的void*无论如何忘掉指针总是个好主意

当一个值类型被加框(作为一个对象利用)时对象类型就被使用了这一章稍后会讨论到加框和消框

类类型

一个类类型可以包含数据成员函数成员和嵌套类型数据成员是常量字段和事件函数成员包括方法属性索引操作符构造函数和析构函数类和结构的功能是非常相似的但正如前面所述结构是值类型而类是引用类型

和C++相比仅允许单继承(你不能拥有派生一个新对象的多重基类) 但是C#中的一个类可以派生自多重接口该接口在下一节将得到描述

第五章 专门讨论使用类编程这一节仅打算给出C#类在哪里适合类型图的一个全貌

接口

一个接口声明一个只有抽象成员的引用类型跟C++中相似的概念为一个结构的成员且方法等于如果你不知道那些概念的任何东西这里就是在C#中一个接口实际所做的仅仅只存在着方法标志但根本就没有执行代码这就暗示了不能实例化一个接口只能实例化一个派生自该接口的对象

可以在一个接口中定义方法属性和索引所以对比一个类接口有什么特殊性呢?当定义一个类时可以派生自多重接口而你只能可以从仅有的一个类派生

你可能会问OK但我必须实现所有的接口成员那么我能从这个途径得到什么呢? 我想举一个来自NET的例子

很多类实现了IDictionary 接口你可以使用简单的类型转换访问接口

IDictionary myDict = (IDictionary)someobjectthatsupportsit

现在你的代码可以访问字典了可等等我说很多类可以实现这个接口——所以你可以在多个地方重用代码来访问IDictionary 接口!一旦学会任何地方都可使用

当你决定在类设计中使用接口时学习更多关于面向对象的设计是个好主意这本书不能教你这些概念但你可以学习如何创建接口以下的代码段定义接口IFace它只有一个方法

interface IFace

{

void ShowMyFace()

}

正如我所提到的不能从这个定义实例化一个对象但可以从它派生一个类因此该类必须实现ShowMyFace抽象方法

class CFaceIFace

{

public void ShowMyFace()

{

ConsoleWriteLine(implementation

}

}

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

代表元

一个代表元封装了具有一些标志的一个方法基本上代表元是类型安全和函数指针的安全版本(回调功能)可以同时在一个代表元实例中同时封装静态和实例方法

尽管你可以用代表员当作具有方法但它们的主要用途是拥有有一个类事件再次我想把你引到下一章那里会详细地讨论类

字符串类型

C程序员可能会诧异但当然C#有一个用于操作字符串数据的基本字符串类型字符串类直接派生自对象且它是被密封的这意味着再不能从它派生类就象其它类型字符串是预定义类System String的一个别名

它的用法十分简单

string myString = some text

合并字符串同样简单

string myString = some text + and a bit more

而如果你想访问单个字符所要做的就是访问下标

char chFirst = myString[]

当比较两个字符串是否相等时简单地使用==比较操作符

if (myString == yourString) ……

我只不过想提到尽管字符串是一个引用类型比较时是比较值而不是比较引用(内存地址)字符串类型几乎用于这本书的每一个例子中而且在这些例程中我会介绍给你一些由字符串对象所显露的极其有趣的方法

数组

一个数组包含有通过计算下标访问的变量所有包含于数组中且被当作元素的变量必须是同一类型这种类型自然被称为数组类型数组可以存储整数对象字符串对象或者 你提出的任何对象

数组的维数就是所谓的排(rank)它决定了相关数组元素的下标数最常用的数组是一维数组(第一排)一个多维数组具有的排数大于 每个维的下标始于终于维的长度减

应有足够的理论支持让我们看一下用一个数组初始化器( array initializer)初始化的数组

string[] arrLanguages = { C C++ C# }

该简写效果等同以下

arrLanguages[]=C arrLanguages[]=C++ arrLanguages[]=C#

而编译器为你做了所有的工作当然它将同样为多维数组初始化器工作

int[] arr = {{} {} {}}

它是以下的简写

arr[] = arr[] =

arr[] = arr[] =

arr[] = arr[] =

如果你不想事先初始化一个数组但知道了它的大小该声明就象这样

int[] myArr = new int[]

如果数组的大小必须动态地被计算用于数组创建的语句可以象这样写

int nVar =

int[] arrToo = new int[nVar]

正如我在这一节开始所陈述的你可以往数组里面塞任何东西只要所有的元素类型都相同因此如果你想把任何东西放进一个数组就声明它的类型为对象

加框和消框

这一章的课程中我已经给出了各式各样的值类型和引用类型由于速度的原因你会使用值类型——它除了占据一定空间的内存块外就没有什么了但是有时对象的方便性就象值类型一样好用

这就是加框和消框登上了舞台的地方加框和消框是C#类型系统的核心概念通过允许一个值类型转换成类型对象或从类型对象转换成值类型这种机制形成了值类型和引用类型之间的捆绑连接任何东西终究是一个对象——但是仅当需要它们是对象时

加框转换

给一个值加框指隐式地把任何值类型转换成类型对象当一个值类型被加框时一个对象实例就被分配且值类型的值被拷贝给新的对象看以下例子

int nFunny =

object oFunny = nFunny

第二行的赋值暗示调用一个加框操作nFunny整型变量的值被拷贝给oFunny对象现在整型变量和对象变量都同时存在于栈中但对象的值居留在堆中那么它暗示着什么呢?它们的值互相独立——在它们之间没有连接(oFunny没有引用nFunny的值) 以下代码说明了结果

int nFunny =

object oFunny = nFunny

oFunny =

ConsoleWriteLine({} {} nFunny oFunny)

当代码改变oFunny的值时nFunny的值并没有改变只要你脑袋中有这个copy动作就能够使用值类型的对象功能发挥出你的巨大优势!

消框转换

和加框相比消框是显式操作——必须告诉编译器你想从对象中抽取出哪一种值类型当执行消框操作时C#检测所请求的值类型实际上存储在对象实例中经过成功的校验该值被消框

这就是消框如何执行

int nFunny =

object oFunny = nFunny

int nNotSoFunny = (int)oFunny

如果错误地请求一个double值

double nNotSoFunny = (double)oFunny

通用语言运行时(Common Language Runtime简写CLR)将会引发一个InvalidCastException异常你可以在第异常处理 中学到更多有关异常处理的知识

小结

在这一章中你学到了C#中用到的各种类型简单的值类型包括整型布尔型浮点型和小数型你会非常经常地用到一些类型进行数学和金融的计算还有逻辑表达

在介绍引用类型之前我显示了一个看起来象类的结构类型它几乎如一个类般地运作但它只是一个值类型这使它更加适合需要有大量的小对象的场合引用类型起始于所有对象之母的objedt本身object是C#中所有对象的基类且它同样用于值类型的加框和消框除此之外我还让你领略了代表元字符串和数组

令C#程序员十分神气的类型就是类它是C#面向对象编程的心髒下一章整章专门让你迅速理解这个激动人心且功能强大的类型

               

上一篇:一个.NET平台下通用的串口操作类

下一篇:Visual Studio 2008改进版体验