在本章中我們將介紹複雜的資料集使用方法, 我們先從陣列的介紹開始, 陣列是用來收集相似資料, 例如你可以建立朋友姓名的陣列 ( 在本章稍後將會實際建立 ), 然後將會討論如何使用列舉方法, 讓先前定義的資料集可以被使用 ( 避免你輸入錯誤的值 ), 常數將是下一個要介紹的主題, 我們將會介紹它們用常數來改善程式碼的維護性, 然後介紹結構 (structure) 的使用方法 ( 它與類別相類似 ), 然後介紹建立強大的集合類別來維護和產生複雜的資料列 陣列 當撰寫軟體時相當常見的需求就是將相似或相關的資料具有暫存的能力, 我們可使用陣列提供此功能, 陣列是單一資料型態的資料列表, 舉例來說, 你也許要使用整數陣列儲存朋友年齡或是使用字串陣列儲存姓名 在本節中, 我們將會介紹如何定義陣列 產生陣列和在應用程式中使用陣列 定義和使用陣列 當我們定義陣列時, 我們實際上建立了超過單一維度的變數, 舉例來說, 若我們定義一個字串變數如下, 我們只能夠儲存單一字串值在其中 : Dim s As String
第六章 然而, 當我們建立了一種多重效應的變數陣列時, 你可在單一變數中儲存超過一個以上的值, 陣列的定義方式是在變數名稱後輸入陣列的大小, 因此若我們要定義長度為 10 的字串陣列, 我們可定義如下所示 : Dim s(9) As String 為何我們使用 (9) 而非 (10) 來代表陣列長度 10 的原因將在稍後詳細解釋, 現在只要簡單的知道因為陣列是以 0 為起始陣列, 因此第一個使用陣列 0, 第二個使用陣列 1, 以此類推 當我們有陣列時, 我們可以使用索引值 0 到最大的可能索引值, 存取單獨的陣列元素, 此最大的可能索引值比總陣列大小少一 因此在陣列使用索引值 2 設定元素, 可使用如下的語法 : s(2) = "Disraeli" 要取回相同的元素, 可使用下列語法 : MessageBox.Show(s(2)) 當你對其它陣列元素設定時, 原陣列元素內的值將不受影響, 因此若我們做如下設定時 : s(3) = "Winston" s(2) 仍然維持 "Disraeli" 要瞭解陣列的使用方法最簡單的的方式就是撰寫使用陣列的程式碼 實作練習 定義和使用簡單陣列 1. 使用 Visual Studio.NET 建立新的 Windows 應用程式專案, 命名為 Array Demo 2. 當 Form1 設計檢視出現時, 加入 ListBox 控制項到 form 上, 使用屬性視窗設定 Name 屬性為 lstfriends,integralheight 屬性設定為 False( 此代表 listbox 不能改變大小, 但能顯示部分項目 ) 6-2
3. 現在加入 Button 控制項到 form 上, 設定 Name 屬性為 btngo, 設定 Text 屬性為 Go, 現在 form 應該如下圖所示 : 4. 在 Go 按鈕上雙擊滑鼠, 加入下列程式碼 : Private Sub btngo_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btngo.click ' define an array to hold friends in... Dim friends(4) As String ' store the name of each friend... friends(0) = "Darren" friends(1) = "Edward" friends(2) = "Alex" friends(3) = "Charlotte" ' add Alex to the list... lstfriends.items.add(friends(2)) 5. 執行專案, 點選 Go 按鈕你將可見到結果如下圖所示 : 運作原理 當我們定義陣列時要指定資料型態和陣列大小, 在本例中我們指定字串型態陣列並且定義陣列大小為 5: 6-3
第六章 Private Sub btngo_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btngo.click ' define an array to hold friends in... Dim friends(4) As String 陣列大小的定義有一點古怪, 你必須指定比你要的大小少 1 的數字 ( 稍後將會解釋 ), 因此我們使用下列程式碼 : Dim friends(4) As String 這樣我們就定義了大小為 5 的陣列, 換句話說我們定義了有 5 個元素的陣列 定義完陣列後, 我們就擁有自己的陣列並且可以使用索引來存取陣列內的每一個項目, 索引是在陣列名稱後的刮號內加入指定的數字, 索引的起始值為 0, 並往上遞增直到比陣列內元素個數少一的數字為止, 下列程式碼我們將所有五個陣列元素設定名稱 : ' store the name of each friend... friends(0) = "Darren" friends(1) = "Edward" friends(2) = "Alex" friends(3) = "Charlotte" 與使用索引設定陣列內項目相同的方法, 我們可以使用索引將陣列內的項目取出, 在本例中, 我們要求取出索引值 2 的項目, 也就是在陣列內第三個項目的 Alex: ' add Alex to the list... lstfriends.items.add(friends(2)) 索引和大小看起來不一致的原因是因為索引是以零為基底開始的, 在一般人類的邏輯上傾向於以 1 為開始計數, 在我們的陣列定義上, 我們依照最大索引邊界值來指定陣列大小, 或是陣列所要支援的最高索引值, 通常來說, 當我們加入或取得陣列值時, 我們必須向下調整到實際的索引值, 舉例來說第五個索引實際上是在第四個位置, 第一個索引是在第零個位置上, 以此類推 6-4
使用 For Each Next 我們使用陣列上最常用的方法之一就是結合 For Each...Next 迴圈, 在第三章中已經介紹過, 但我們是使用在 Framework 類別回傳的集合物件上, 以下就介紹 For Each...Next 如何與陣列結合使用 實作練習 使用 For Each Next 結合陣列 1. 若程式還在執行狀態請先關閉, 開啟 Form1 的程式碼編輯器, 並修改 btngo_click 事件程序, 如下所示 :... ' go through each friend... Dim friendname As String For Each friendname In friends Next ' add each one to the list... lstfriends.items.add(friendname) 2. 執行專案並點選 Go 按鈕, 將會見到下圖畫面 : 運作原理以上我們見到 For Each...Next 迴圈將 Framework 回傳的集合物件循環讀出, 在此例中我們是使用在陣列上, 相同的原理, 我們在開始時建立控制變數與陣列相同的型態, 在迴圈內部是從陣列的第 0 個元素開始直到最後一個元素, 每次循環我們可以檢查控制變數的數值和對它進行運用, 在本例中, 我們對它進行加入名稱到 lstfriends 的清單中 6-5
第六章 請注意加入清單中的順序與出現在陣列中的次序是相同的, 這是因為 For Each...Next 是依照它們定義的次序來進行的原因 傳遞陣列參數 將陣列 ( 可以是一列數值清單 ) 視為參數傳遞到函數中是非常有用的方法, 在本節中我們將會介紹如何使用此方法 實作練習 傳遞陣列參數 1. 開啟 Form1 程式碼編輯器, 將迴圈加入到分開函數中, 程式碼如下 : Private Sub btngo_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btngo.click ' define an array to hold friends in... Dim friends(4) As String ' store the name of each friend... friends(0) = "Darren" friends(1) = "Edward" friends(2) = "Alex" friends(3) = "Charlotte" Sub AddFriendsToList(ByVal friends() As String) ' go through each friend... Dim friendname As String For Each friendname In friends ' add each one to the list... lstfriends.items.add(friendname) Next 2. 現在將 btngo_click 內的程式碼更改如下 :... ' show the friends... 6-6
AddFriendsToList(friends) 3. 執行專案並點選 Go 按鈕, 將會見到與之前相同的結果 : 運作原理 此部分的技巧就是告訴函數, 參數是字串型態的陣列, 我們使用空的括號, 如下所示 : Sub AddFriendsToList(ByVal friends() As String) 若我們指定陣列但未指定大小 ( 或上界值 ), 就代表我們告訴 VB 我們不知道也不在乎此陣列的大小, 我們可以傳入任何大小的陣列到 AddFriendsToList 中, 此處我們傳入原始的陣列 : ' show the friends... AddFriendsToList(friends) 但是, 若我們定義另一個不同大小的陣列會發生什麼事呢? 實作練習 加入更多朋友名單 1. 開啟 Form1 程式碼編輯器, 加入下列程式碼到 btngo_click 方法中 :... ' store more friends... Dim morefriends(1) As String morefriends(0) = "Zoe" morefriends(1) = "Ollie" ' show the friends... AddFriendsToList(friends) AddFriendsToList(moreFriends) 6-7
第六章 2. 執行專案並點選 Go 按鈕, 將會見到下圖畫面 : 運作原理 以上我們證明的是我們傳入的陣列不必是固定大小的陣列, 我們建立新的大小為 2 的陣列, 並傳入到相同的 AddFriendsToList 函數中 當你撰寫程式碼時, 你可以由 IntelliSense 的顯示結果, 看出空的括號代表陣列型態的參數, 如下圖所示 : 我們不只可以看到 friends 是陣列型態, 也可以知道陣列的資料型態是字串 陣列排序 有時候排序陣列是非常有用的, 在本章節中, 我們將要介紹如何將陣列依照字母排序 實作練習 陣列排序 1. 開啟 Form1 程式碼編輯器, 找到 AddFriendsToList 方法, 加入下列程式碼 : Sub AddFriendsToList(ByVal friends() As String) ' sort it... Array.Sort(friends) ' go through each friend...... 6-8
2. 執行專案並點選 Go 按鈕, 將會見到下圖畫面 : 運作原理所有的陣列在內部都是實作 System.Array 類別, 在本例中, 我們要在類別上使用共用的方法 Sort, 它需要傳入單一參數, 就是你要排序的陣列名稱, 依據陣列的資料類型,Sort 方法將會依照預設的建議幫你排序, 在本例中我們是字串陣列, 因此陣列依照字母排序 若我們要使用在包含整數或是浮點數的陣列, 此陣列會依照數字作排序 反向存取 For Each...Next 只會依照單一方向前進, 它從位置 0 開始並進行迴圈直到陣列結束, 若我們要反向進行 ( 從陣列長度減一到位置 0), 我們必須使用標準的 For...Next 迴圈 實作練習 反向存取 1. 在 Form1 中移除第二個定義的陣列和第二個呼叫的 AddFriendsToList, 因此你回到之前所完成的程式 : Private Sub btngo_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btngo.click ' define an array to hold friends in... Dim friends(4) As String ' store the name of each friend... friends(0) = "Darren" friends(1) = "Edward" 6-9
第六章 friends(2) = "Alex" friends(3) = "Charlotte" ' show the friends... AddFriendsToList(friends) 2. 經過修改後,AddFriendsToList 就如同下列程式碼 : Sub AddFriendsToList(ByVal friends() As String) ' sort it... Array.Sort(friends) ' how big is the array? Dim upperbound As Integer = friends.length - 1 ' go through each friend... Dim index As Integer For index = upperbound To 0 Step -1 Next ' add each one to the list... lstfriends.items.add(friends(index)) 3. 執行專案並點選 Go 按鈕, 將會見到 friends 內容清單將會反序排列, 陣列經過排序, 陣列項目依照反序排列方式加入清單中, 因此我們見到相反的排列順序,Len 先加入, 然後是 Edward, 接著是 Darren 依此類推 6-10
運作原理當我們給定陣列在 AddFriendsToList 時, 我們並不知道它實際大小是多少, 然而可以使用 Length 屬性來找出陣列大小, 從陣列大小值減一就可以得到上界值, 換句話說就是陣列的最大索引值 : ' how big is the array? Dim upperbound As Integer = friends.length 1 當取得上界值後, 我們就可以設定 For...Next 迴圈一次存取一個陣列的索引值, 並可以反向存取 : ' go through each friend... Dim index As Integer For index = upperbound To 0 Step -1 ' add each one to the list... lstfriends.items.add(friends(index)) 隨機存取 我們已經介紹過如何由單一方向存取陣列, 並反向回頭存取, 現在我們要介紹如何隨機存取陣列 實作練習 隨機存取 1. 加入下列程式碼到 AddFriendsToList: Sub AddFriendsToList(ByVal friends() As String) ' sort it... Array.Sort(friends) ' how big is the array? Dim upperbound As Integer = friends.length ' create a randomizer... Dim random As New System.Random() ' count ten items... Dim n As Integer For n = 1 To 10 ' which index? Dim index As Integer = random.next(upperbound) lstfriends.items.add(index & ": " & friends(index)) 6-11
第六章 Next 2. 執行專案並點選 Go 按鈕, 將會見到下圖畫面 : 運作原理.NET 的隨機數值產生器 ( 實作 System.Random) 可以用來建立隨機號碼, 在本例中, 每次的迴圈中, 我們要求隨機數值產生器產生從 0 到 upperbound 的數值, 換句話說就是陣列長度, 傳入 Random 類別的 Next 方法中的參數是獨立的, 因此每次迴圈都要傳入 : Dim upperbound As Integer = friends.length ' create a randomizer... Dim random As New System.Random() ' count ten items... Dim n As Integer For n = 1 To 10 ' which index? Dim index As Integer = random.next(upperbound) lstfriends.items.add(index & ": " & friends(index)) UBound 和 LBound 我們已經介紹過使用陣列的 Length 屬性可以取得陣列的大小值, 然而在 Visual Basic.NET 中有兩個關鍵字可用來決定陣列的上下界值 UBound 和 LBound 是 Visual Basic.NET 指定的關鍵字, 用來回傳陣列的最大索引值和最小索引值 6-12
實作練習 UBound 和 LBound 1. 找到 AddFriendsToList 方法並加入下列程式碼 : Sub AddFriendsToList(ByVal friends() As String) ' upper and lower... MessageBox.Show("Upper bound: " & UBound(friends), "Array Demo") MessageBox.Show("Lower bound: " & LBound(friends), "Array Demo") ' sort it... Array.Sort(friends)... 2. 執行專案並點選 Go 按鈕, 將會見到下圖畫面 : 3. 點選 OK 按鈕, 將會見到下圖畫面 : 運作原理 UBound 和 LBound 是退回上一代使用的 VB, 此就是為何這些冒險的類型已不在 C# 中找到 ( 或其它的.Net 語言 ), 在之前的版本是可以設定非 0 的陣列下界值, 在 Visual Basic.NET 中卻是不可以如此設定的, 因此 LBound 永遠回傳 0 陣列初始值 在 Visual Basic.NET 中可以在同一行程式碼中建立陣列並設定初值, 而不用另外撰寫程式碼 ( 如下所示 ), 一一為陣列元素設定初值 : ' store the name of each friend... 6-13
第六章 friends(0) = "Darren" friends(1) = "Edward" friends(2) = "Alex" friends(3) = "Charlotte" 實作練習 陣列初始值 1. 找到 btngo_click 事件控制並異動下列程式碼 : Private Sub btngo_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btngo.click ' define an array to hold friends in... Dim friends() As String = {"Darren", "Edward", "Alex", _ "Charlotte", "Len"} ' show the friends... AddFriendsToList(friends) 2. 執行專案, 結果將會如同之前的執行結果 運作原理大括號 {} 可讓我們直接幫陣列設定初始值, 在本例中, 我們輸入五個初始值到陣列中, 並用逗號隔開 請注意用此方法時, 我們並沒有指定陣列的上界值, 相反的我們是使用空括號,Visual Basic.NET 會幫我們計算我們輸入的上界值 當要產生較大的陣列時, 此技術就非常不適用, 若你的程式要產生大的陣列, 你也許要使用我們之前介紹的方法, 指定陣列位置和陣列內容 列舉 目前為止, 我們所見過的變數實際上並沒有限制儲存在其中的資料類型, 若我們定義變數為 Integer 型態, 我們可以放任何數字在其中, 在 String 和 Double 型態也相同, 然而我們也已經見過只有兩種可能值的變數 :Boolean 型態的變數可以是 True 或是 False 6-14
通常在撰寫程式時, 要限制某些可能的值儲存在變數中, 舉例來說若你需要儲存門窗數和車輛數的變數, 你真要儲存 163,234 嗎? 列舉 (Enumeration) 可建立於以下的基礎上 :Integer Long Short 或 Byte 建立新的變數型別, 此變數可設定成一組你定義過的數值, 理想狀態下可避免你使用無效的值, 因為它可以描述特定的值, 因此可用來提供程式碼的清晰度, 在本節中, 我們將介紹如何建立應用程式找出一天的時間, 在此基礎上可以記錄以下 DayAction 的可能值 : Asleep Getting ready for work Traveling to work At work At lunch Traveling from work Relaxing with friends Getting ready for bed 實作練習 使用列舉型態 1. 使用 Visual Studio.NET 建立新的 Windows 應用程式專案, 命名為 Enum Demo 2. 列舉型態通常定義為要使用它的類別成員 ( 然而在本例中並不需要 ), 當開啟 Form1 設計工具時, 打開程式碼編輯器, 加入下列程式碼到最頂端 : Public Class Form1 Inherits System.Windows.Forms.Form ' enum... Public Enum DayAction As Integer Asleep = 0 GettingReadyForWork = 1 TravelingToWork = 2 AtWork = 3 AtLunch = 4 TravelingFromWork = 5 RelaxingWithFriends = 6 GettingReadyForBed = 7 End Enum 6-15