本篇要分享的內容包含Enum、Dictionary、Stack、Queue、IComparable<T>、IComparer<T>、CompareTo、Compare等等相關內容。它們與Array和List有些類似,都是資料集合存取或資料其他相關處理的部分,我們就來看一看它們是何方神聖吧~
一、列舉Enum
顧名思義就是列出有哪些內容並且會用名稱來代表數字,通常用在判斷狀態下使用,最大的用途就是可以幫助我們提升程式的易閱讀性,在使用Enum時它會以預設的uint形態下儲存到記憶體裡,它允許的型別包含:byte、sbyte、short、ushort、int、uint、long、ulong等。
所以說當我們在Enum中依序寫了睡覺、吃飯、玩樂這三件事,那麼睡覺就代表0,吃飯就代表1、玩樂就代表2以此類推,除非有特別去定義說睡覺是5,那麼吃飯就會是6,玩樂就會是7,數字是慢慢累加上去的,若每個狀態都會給予相對應數字的話,寫入Enum的狀態順序就不這麼重要了,就看偉大的設計師您想要怎麼設計囉~
那麼也因為是這樣的狀況像是switch...case...這個條件式選擇,通常會出現case 0、case 1、case 2...這樣的程式,數字也是累加上去,每一個也都代表不同條件或狀態,因此也很適合使用Enum用在這邊,醬就會更容易讀取程式了,不用擔心說:咦?0是指什麼?1又是指什麼?又還要回去翻找的狀況發生。
這邊利用UNO牌來跟大家說明好哩~也順便檢視一下自己熟練程度,應該多多少少有玩過吧!這邊我們暫時先不把黑色特別牌放進來,牌的種類有四種顏色、每種牌都有數字或是功能用途,就來跟大家介紹Enum怎麼使用。
實例:UNO抽牌
說明:
【Enum】:這邊我使用兩個Enum,一個是對於顏色分類,另一個是數值。把我們想要分類的內容放進來。
【類別】:
(1)第15-29行:這邊是跟主程式去做傳遞值的部分
(2)第15行:使用的參數會使用到enum,因此在寫這個參數的時候,就會是先寫enum的命名再寫變數,也就是Color color,前者是enum的分類命名後者是變數
(3)第21-29行:由於取得的值是屬於enum,因此要顯示字串則使用「.ToString()」轉為字串
(4)第31-53行:這邊是利用switch...case...來使用enum,這邊的case後面不是跟著數字,而是直接顯示enum中的該內容,也就是Color.red....這樣的表示方式。這邊執行的內容就是將抽取的顏色從英文轉換為中文文字。
【主程式】:
(1)第21行:因為我們要做的事是抽牌會用到亂數,所以先建立它。
(2)第25行:這邊就是照常建立物件(類別的格式)
[參數部分]->由於我們的亂數是對於enum裡的內容做隨機抽取,因此在random前面加入(Enum的分類命名),也就是程式裡寫的(Color)random.Next(4),這樣的寫法
(3)第26行:用文字顯示抽牌結果
(4)第28行:這邊就是去執行類別中的Switch部分
(5)第29行:這邊就是將Switch執行完的結果,在label1下一行顯示出來。
(6)第31行:這是用相對位置顯示抽中的該圖片(往後會再提)
二、字典Dictionary
它的功能很像List可以處理很多型別也可以存放任何東西,包括字串、數字、物件都可以存取哦!它跟字典很像,把一些資料輸入進去後可以用查詢方式找到我們想要的資料,主要用途就是只要一個鍵(key)就可以去尋找相對應的資料或內容值,此內容值可以是Array、List都可以。
使用Array、List要處理資料可能就需要做整批做處理會運用到迴圈,然而Dictionary這個就只要找到key就可以提取一個或該組資料內容出來了。
1.看一下Dictionary用法:
Dictionary<資料型態1 , 資料型態2> 變數名稱 = new Dictionary<資料型態1 , 資料型態2>();
2.增加項目資料
變數名稱.Add(內容值a , 內容值b);
3.查詢項目資料
string findData = 變數名稱[內容值a];
4.刪除項目資料
變數名稱.Remove(內容值a);
5.計算Dictionary中key的數量
int keyNum=變數名稱.Count;
三、堆疊Stack & 佇列Queue
這兩個都是屬於群集(Collection)部分,並且都是對於有特定順序的方式來處理資料,堆疊(Stack)是像疊羅漢一樣先進後出(First-in Last-out)的方式在處理資料;佇列(Quene)是像排隊買東西一樣先進先出(First-in First-out)的方式在處理資料。故若想從它們資料中去取出內容值的話,取出後該值就不會在那堆資料中,因為已經被拿出來了。
堆疊(Stack)是使用push將內容值放入stack中,然而使用pop將內容值從stack中取出,由於資料像是疊羅漢一樣第一個放進去的就會在最底下,那麼要取中間的值必須把壓在它上面的都拿掉才可以取得。
1.堆疊(Stack)使用方法:
Stack<資料型態> 變數=new Stack<資料型態>();
變數.Push(內容值); //放入內容值
資料型態 LookValue=變數.Peek(); //查看最後一個的內容值(只是查看而已)
資料型態 getValue=變數.Pop(); //取值
int countNum=變數.Count(); //計算內容值共有多少數量
變數.Clear(); //清除所有內容值
佇列(Queue)是使用enqueue來增加內容值,取出內容值則是使用dequeue,由於它像排隊一樣增加內容值是從後面加入進去的,取出則是從前面取出的,因此當我們從前面取出內容值的時候,原本此值的後面所排列的內容就會往前遞補,如同排隊第一個離開隊伍後,後面的人就會跟著往前遞補上去了。
這邊要注意的是!!它也很像串燒一樣是不能從中間的索引值去增加或刪除內容值的哦!
2.佇列(Queue)使用方法:
Queue<資料型態> 變數=new Queue<資料型態>();
變數.Enqueue(內容值); //
資料型態 LookValue=變數.Peek(); //查看最後一個的內容值(只是查看而已)
資料型態 getValue=變數.Dequeue(); //取值
int countNum=變數.Count(); //計算內容值共有多少數量
這兩個Stack和Queue可不可以放入List裡面呢?是可以的!他們之間轉換關係可以這麼做:
執行結果(Stack、Queue、List 轉換)
倘若你想要使用foreach迴圈去取得裡面的值做轉換也還是可以的,只是要看我們要怎麼去使用這些工具而已。
說明:
(1)我們使用label來顯示結果可以看到一件事,對於stack和queue只要取出內容值後裡面的資料都會被刪除,所以一開始計算共有多少數量時原本為3個,到最後再計算一次就變為0個了。那麼List就不一樣,取資料後它並不會把資料做刪除的哦!
(2)用圖示來看一下它們的運作過程:
(3)所以說對於堆疊(Stack)和佇列(Queue)使用Peek查看資料的時候,就會是Stack最上面的值以及Queue最前面的值哦!
四、IComparable<T>、IComparer<T>、CompareTo、Compare相關用法
對於資料還有這幾個工具它們是比較大小和排序的概念,遇到字串則是比較字母順序,數字就按照它的大小排列這沒有問題。
有看到IComparable、IComparer這兩個它們的開頭都是I,也就是說它們都屬於「介面」哦!所以說若使用這個介面就代表要去實作它,那麼它們裡面只有一個CompareTo或者Compare這個方法是可以與另一個物件做比較的,它會搭配內建的Sort去做排列。
1.不是有了Sort功能可以做排序了嗎?為何還會有這個工具呢?
是因為這個功能排序方法是可以依照我們想要的規則去做排列的哦!甚至是可以去結合使用列舉Enum來當作排序的依據做排列,這樣想要按自己設定的規則方式做排列就可以選擇此工具了,然而若對於List只用Sort,沒有搭配此工具就是依照預設的數字大小或字母順序做排列的,並無法按我們的想要的方法去做排列哦!
2.實例1:IComparable<T>和CompareTo用法
Step1:建立類別(ClassDog)將要比較的欄位需用public,使用IComparable<ClassDog>實作,並且使用CompareTo的方法
Step2:建立列舉(EnumDogKind),把想要排序的順序列出來
Step3:在主程式中建立List把要比較的類別放入List的資料型態中,並且建立List內容
Step4:主程式中建立完List後使用Sort去做排列
看一下實際程式狀況:
說明:
【ClassDog】:由於要用自己的規則做排列,因此實作IComparable介面就是在ClassDog後面加入:IComparable<ClassDog>
(1) IComparable<放的是要比較的類別>
(2)欄位部分就是將要比較的EnumDogKind當作規則,因此就將它先設一個變數為Kind
(3)此類別因為使用了IComparable介面,故此類別要使用CompareTo這個方法
(4)CompareTo(這邊的參數就是放要比較的類別)
(5)第17-28行:這邊就是去做排列的處理動作,依序兩個兩個去做比較排列,然而比較的內容這邊以Kind為主,規則是以列舉Enum的順序去做排列。
註:想要使用年齡來排序,CompareTo寫法就會是
類別_修改為Age來排列寫法(使用IComparable介面排序)
【Enum】:這邊就依照想要的規則依序列舉出來
【主程式】:
(1)List建立是以ClassDog為資料型態,因此新增的內容可以使用類別中使用public定義的欄位內容,也就是Kind和Age。由於Kind是使用EnumDogKind類別,因此它的值就使用EnumDogKind底下的內容。
(2)建完後做Sort排列。可以把中斷點放在這邊(點選行數旁邊位置),接著再按F11可以進入函式逐步執行程式,看一下程式是怎麼運行的哦!中斷點就想下圖,執行的時候就會停在這裡。
(3)接著想要看一下排列後的結果就使用Foreach迴圈,我們使用label來顯示結果。
3.實例2:IComparer<T>和Compare用法
說明:
倘若你還要運用以Age為主來做排列,那麼就可以使用ICompare介面
(1)再新增一個類別名稱多加入Compare,由於要使用ICompare介面,因此在此類別後也要使用:ICompare<比較的類別>,這個比較類別也就是ClassDog這個類別
(2)那麼這個介面也必須使用Compare這個方法,因此也要將它寫入此類別中,然而它的參數會是以ClassDog這個類別為主,並且為2個參數,裡面寫的內容也就是要做排序的程式內容。
(3)【主程式】:由於我們要使用的排列是新建的類別(也就是ClassDogComparer),因此要新建立一個物件後,再去做Sort排列並且參數為新建的類別名稱變數。
大家可以看一下這兩者之間的排列差異在哪裡,接下來說一下這兩者的差別:
4.IComparable<T> V.S. IComparer<T> 差別
想要對於自訂義方式做比較的話就使用IComparable<T>、IComparer<T>。當我們只需使用一個做比較的話,就可以使用IComparable<T>,若你還要再用其他的欄位做比較的話,也就是兩個以上要做比較的話,就再用IComparer<T>
工具手法有很多種,所以我們除了了解這些工具外,學習如何舉一反三並且靈活運用也是學程式重要的一環哦!
目前的我們就是要先知道有哪些工具可以使用,等到程式寫多了就可以開始訓練自己靈活運用使用各種手法來呈現,一開始先使用自己會的工具來呈現成果沒關係,過程中再慢慢學習各種工具去累加自己的程式工具箱,熟練了就隨時都可以拿出來使用了唷~
倘若能力足夠就可以去分析使用什麼樣的工具寫法會更好,程式會更簡短或是更容易讀取哦~