09 使用枚举和结构创建值类型

1.使用枚举

假定要在程序中表示一年四季。可用整数0,1,2和3分别表示Spring(春),Summer(夏)、

Fall(秋)和Winter(冬)。这虽然可行,但并不直观。如果代码中已经使用了整数值0,那么经常搞不清楚-一个特定的0是否代表Spring。另外,这也不是一种十分可靠的方案。例如,假定声明了名为season的int变量,那么除了0, 1, 2和3,其他任何合法的整数值都可以赋给它。C#提供了更好的方案。可以使用enum 关键字创建枚举类型,限制其值只能是一组符号名称。

 

1.1声明枚举

比如上面的例子,现在我们声明一个Season枚举:

enum Season { Spring,Summer,Fall,Winter}

1.2使用枚举

enum Season { Spring,Summer,Fall,Winter}

class Example
{

    private Season currentSeason;//作为字段

    public void Medth(Season parameter)  //作为方法参数    
    {

        Season localVariable;  //作为局部变量
        localVariable = Season.Fall;  //不能单独写Fall,每个枚举定义的字面值名称都只有这个枚举类型的作用域。
        Console.WriteLine(localVariable);  //输出“Fall”

    }

}

从上面的一段代码我们可以看出,我们可以像使用其它任何类型那样使用它们。

 

1.3选择枚举字面值

枚举内部的每个元素都关联(对应)一个整数值。默认第一个元素对应整数0,以后每个

元素对应的整数都递增1。可将枚举变量转型为基础类型,然后获取其基础整数值。

例如,下面在控制台上输出值2,而不是单词Fall(Spring对应0,Summer对应1,Fall对应2,Winter对应3):

enum Season {Spring,Summer,Fall,Winter}

…

Season colorful = Season.Fall;

Console.WriteLine((int)colorful);  //输出2

可以将特定整数常量和枚举类型的字面值手动关联起来。

例如:

Enum Season {Spring = 1,Summer,Fall,Winter}

多个枚举字面值可具有相同的基础值。例如英国的秋天是Autumn而不是Fall。为了适应两个国家的语言文化,可声明以下枚举类型:

enum Season {Spring,Summer,Fall,Autumn = Fall,Winter}

 

1.4选择枚举的基础类型

声明枚举时,枚举字面值默认是int类型。但是,也可让枚举类型基于不同的基础整

型。例如,为了声明Season的基础类型是short而不是int,可以像下面这样写:

enum Season : short {Spring,Summer,Fall,Autumn = Fall,Winter}

 

这样做的主要目的是节省内存。int占用内存比short大:如果不需要int那么大的

取值范围,就可考虑使用较小的整型。

枚举可基于8种整型的任何一种: byte, sbyte, short, ushort, int, uint, long或者ulong.枚举的所有字面值都不能超出所选基础类型的范围。例如,假定枚举基于byte数据类型,那么最多只能容纳256个字面值(从0开始)。

 

2.使用结构

上一篇博客讲过,类定义的是引用类型,总是在堆上创建。有时类只包含极少数据,因为管理堆而造成的开销显得不合算。这时更好的做法是将类型定义成结构。结构是值类型,在栈上存储,能有效减少内存管理的开销(当然前提是这个结构足够小)。

结构可包含自己的字段、方法和构造器(但以后会讲到,构造器有一个 重要的区别)。

 

其实我们经常使用的int基本数据类型就是System.Int32这个结构的别名。之前曾用的静态方法int.Parse将字符串转换成对应的整数值,其实就是调用了Int32结构的Parse方法。

这些结构还包含一-些有用的静态字段。例如,Int32.MaxValue对应的是一个int能容

纳的最大值,Int32.MinValue 则是int 能容纳的最小值。

下表总结了C#基元类型及其在MicroofLNET Framework中对应的类型.注意,string

和object类型是类(引用类型)而不是结构。

2.1声明结构

声明结构要以struct关键字开头,后跟类型名称,最后是大括号中的结构主体。语法

上和声明类是一样的。例如,下面是一个名为Time的结构,其中包含三个公共int字段,分别是hours, minutes 和seconds:

struct Time
{
    public int hours,minutes,seconds;
}

和类一样,大多数时候都不要在结构中声明公共字段,因为无法控制它的值。例如,

任何人都能将minutes(分)或seconds(秒)设为大于60的值。更好的做法是使用私有字段,并为结构添加构造器和方法来初始化和处理这些字段。如下例所示:

struct Time
{

    private int hours,minutes,seconds;
    …
    public Time(int hh,int mm,int ss)
    {
        this.hours = hh%24;
        this.minutes = mm%60;
        this.seconds = ss%60;
    }
    public int Hours()
    {
        return this.hours;
    }

}

注意:

复制值类型的变量将获得值的两个拷贝。相反,复制引用类型的变量,将获得对同一

个对象的两个引用。总之,对于简单的、 比较小的数据值,如复制值的效率等同于或基本等同于复制地址的效率,就使用结构。但是,较复杂的数据就要考虑使用类。这样就可选择只复制数据的地址,从而提高代码的执行效率。(如果一个概念的重点在于值而非功能,就用结构来实现。)

 

2.2理解结构和类的区别

(1)不能为结构声明默认构造器(无参构造器)。

之所以不能为结构声明自己的默认构造器,是因为编译器始终都会自动生成一个。

而在类中,只有在没有自己写构造器的时候,编译器才会自动生成默认构造器。

编译器为结构生成的默认构造器总是将字段置为0,false 或null,这和类一样。

(2)类的实例字段可在声明时初始化,但结构不允许。

下表总结了结构和类的主要区别

2.3声明结构变量

定义好结构类型之后,可以像使用其他任何类型那样使用它们。例如,如果定义了名

为Time的结构,就可以创建Time类型的变量、字段和参数。如下例所示:

struct Time
{
    private int hours,minutes,secoonds;
    …
}



class Example
{
    private Time currentTime;

    public void Method(Time parameter)
    {
        Time localVariable;
        …

    }

}

注意:

和枚举一样,可以使用?修饰符创建结构变量的可空版本。然后,可以把null值赋给变量。

Time? currentTime = null;

2.4理解结构的初始化

Time now = new Time();

下图展示了这个结构中的各个字段的状态。

然而,由于结构是值类型,所以不调用构造器也能创建结构变量,如下例所示:

Time now;

在这个例子中,变量虽已创建,但其中的字段保持未初始化的状态。试图访问这些字段会造成编译时错误,如下图所示。

如果写了自己的struct构造器,也可以用它来初始化结构变量。如前所述,必须在自

己的构造器中显式初始化结构的全部字段。例如:

struct Time

{

    private int hours,minutes,seconds;
    …
    public Time(int hh,int mm)
    {
        this.hours = hh;
        this.minutes = mm;
        this.seconds = 0;
    }

}

下例调用自定义的构造器来初始化Time类型的变量now:

Time now = new Time(12,30);

内存图如下:

2.5复制结构变量

我们举2例

(1)

Date now = new Date(2020,Month.Marth,19);

Date copy = now;

(2)

Date now;

Date copy = now;//编译时错误:now未赋值

复制结构变量时, =操作符左侧的结构变量的每个字段都直接从右侧结构变量的对应字

段复制。这是一个简单的复制过程,它对整个结构的内容进行复制,而且绝不会抛出异常。而如果Time是类,两个变量(now和copy)将引用堆上的同一个对象。

 

参考书籍:《Visual C#从入门到精通》

发布了46 篇原创文章 · 获赞 53 · 访问量 3713

猜你喜欢

转载自blog.csdn.net/qq_38992372/article/details/104990641
09