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