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#從入門到精通》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章