c#语言系列讲座(14) 结 构

结 构

类为采用面向对象方式构建可复用组件提供了支持,但有时候我们希望能够获得一种像系统内建的基本类型一样可以方便快速地为之分配内存,并且没有继承引用等负担的轻量级的数据类型。C#中的自定义结构类型为我们提供了这样的实现方式,它尤其适用于构建一些比较小的数据结构。

结构和类非常相似,它们都可以包含域、方法、属性、事件、索引等成员,结构也可以实现多个接口。但结构和类也有很大差异,最典型的是结构为值类型,而类为引用类型。值类型使得结构变量本身包含着结构的数据,这些数据被分配在栈上,而不是像类等引用类型那样分配在托管堆上。值类型是结构最核心的性质,由此衍生出了它的种种行为。结构的赋值是特别需要注意的,看下面的代码:

using System;

struct sPoint{ //点结构

public int x, y;

public sPoint(int x, int y) {

this.x = x;

this.y = y;

}

}

class Test{

static void Main() {

sPoint spa=new sPoint(10,20);//点结构

sPoint spb=spa;

//点结构赋值

spb.x=0;

Console.WriteLine(spa.x+“,”+spa.y);//10,20

Console.WriteLine(spb.x+“,”+spb.y);//0,20

}

}

对结构的赋值导致结构内数据的拷贝,而非引用句柄的拷贝!同样的,作为参数或返回值传递的结构也是对其数据成员的一份新的拷贝。

结构实例构造器和实例成员函数中的this也和类中的this含义有所不同。在类中,this本质上是一个引用句柄值,它不可以再被赋值;而在结构中,this更像一个结构类型的变量,它可以被赋值。

结构类型的缺省值是将它所有的值类型的数据成员设置为对应值类型的缺省值,将其引用类型的数据成员设置为null,而类的缺省值为null。由于结构变量本身总包含着它的数据,不可以将结构变量赋值为null——结构没有引用句柄的概念,自然不能有null值!值类型的缺省值规则使得结构不可以再声明无参数的构造器。对于实例成员,结构不允许在声明的同时进行初始化。但对于静态成员则没有此规定,可以声明实现无参数的静态构造器。结构中不允许声明实现析构器,这是由它的栈分配性质决定的。

一个类变量可以在编译时被隐含地转化为该类的继承基类(如object)变量或其实现的接口类型变量,运用明晰转型也可以逆向进行。那么作为值类型的结构变量如何被转化为object变量或其实现的接口变量?C#引入一种称做box和unbox的操作来进行这种双向的转换。box和unbox操作为值类型和引用类型之间提供了一个转换的桥梁,使得C#中的数据类型得以统一。

当结构变量需要被转换为object变量或其实现的接口变量时,box操作在托管堆上为object变量或接口变量分配空间,并把结构变量的数据拷贝到相应的位置。相反,当object变量或其实现的接口变量被转换为结构变量时,unbox操作使得相应的数据从托管堆内拷贝到结构变量所在的栈上。

枚 举

枚举类型是C#中又一种轻量级的值类型,C#用枚举来表达一组特定值的集合行为,比如Windows窗体可选的状态、按钮控件的风格等。下面的程序代码展示了典型的枚举用法:

public enum WritingStyle{

Classical,

Modern,

Elegant,

}

class Essay {

public void Write(WritingStyle writingStyle) {

switch (writingStyle){

case WritingStyle.Classical:

break;

case WritingStyle.Modern:

break;

case WritingStyle.Elegant:

break;

default:

throw(new System.ArgumentException(“Invalid Writing Style”));

}

}

}

注意上面的枚举符号Classical、 Modern、Elegant之间用逗号“,”而不是分号“;”来分隔,其中最后一个枚举值Elegant之后可以省去逗号分隔符。

和结构一样,C#中的枚举不允许有自己的继承父类System.Enum; 同样的,枚举不能被继承,也没有“abstract”之说。System.Enum类为枚举类型提供了很多好用的功能操作,比如可以通过GetName方法得到声明枚举值的字符串符号表示。下面的例子显示了一些比较常用的操作:

using System;

public enum WritingStyle{

Classical,

Modern,

Elegant,

}

class Test {

public static void Main() {

WritingStyle dw=WritingStyle.Modern;

Console.WriteLine(Enum.GetName(typeof(WritingStyle),dw));

Console.WriteLine(dw.ToString());

Console.WriteLine(Enum.GetUnderlyingType(typeof(WritingStyle)));

}

}

C#的枚举和整数值之间严格区分,比如我们不能在上面的代码中做“dw=1”类似的赋值。但每个枚举值却的的确确都有一个整数类型的数值相对应,而且可以转换,只不过这种转换必须用明晰的转型语法来表达。我们知道在C#中整数类型有byte、 sbyte、 short、 ushort、int、uint、long和ulong共八种,那么C#的枚举值对应的是哪一种整数类型呢?它关系到我们的枚举类型能够容纳的枚举值的数量。实际上C#枚举类型支持这八种整数类型的任何一种,根据需要可以在声明枚举类型的时候来指定,如“public enum WritingStyle :byte”就指定了它的枚举值的整数类型为byte。该类型可以通过上面所述的Enum.GetUnderlyingType方法来获得。如果不明确指定,C#将默认采用int类型作为枚举数值的类型。另外,枚举值也拥有像整数那样的比较、逻辑、算术等操作行为。
阅读更多
个人分类: C Sharp
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭