05 方法
5.1 方法 在一個較大型的程式中,通常會將具有特定功能或經常重複使用的程式,撰寫成獨立的小單元,稱為「方法」(Method),並賦予方法一個名稱,當程式需要時就可以呼叫此方法來執行該段特定程式。(此種重複使用的程式小單元在其他語言中可能稱為程序、副程式或函式, Visual C# 為了達到物件導向精神, 則統稱為方法)。 使用方法的程式設計方式具有下列的好處: 將大程式切割後由多人撰寫,有利於團隊分工,可縮短程式開發的時間。 可縮短程式的長度,程式碼也可重複使用,當再開發類似功能的產品時,只需稍為修改即可以套用。 程式可讀性高,易於除錯和維護。
5.1.1 類別與方法 Visual C# 是物件導向的程式語言,所撰寫出來的應用程式都是由一個或多個類別組成;方法是類別的成員之一,所以方法必須置於類別中。 以主控台應用程式為例,系統設定由 Program 類別的 Main 方法開始執行,所以建立一個主控台應用程式專案時,系統會自動產生下列程式碼:
5.1.2 建立方法 存取修飾詞:存取修飾詞常用的有 public、private 和 protected。public 關鍵字表示方法的存取為共用型態,即允許目前應用程式中的所有類別均可存取;private 關鍵字則表示方法只允許同一類別存取;protected 關鍵字則表示允許同一類別及其子類別存取。若省略關鍵字,系統的預設值為 private。 static:加上 static 關鍵字宣告的方法,稱為「靜態方法」;省略 static 宣告的方法,稱為「案例方法」。在同一類別中可以直接呼叫靜態方法,而不同類別的敘述,則必須以「類別. 靜態方法」呼叫。案例方法在下一章中說明。
回傳值資料型別:方法執行完畢後可以有一個傳回值,回傳值的資料型別即為此處宣告的資料型別,若該方法沒有傳回值則以 void 宣告。 方法名稱:方法名稱和變數命名規則相同,必須使用合法的命名,且在相同的類別中,不可以使用相同的方法名稱 ( 除非是方法多載,方法多載參考 5.4 節)。 參數串列:參數串列可有可無,在宣告方法中參數串列是用來接收傳遞進來的資料,稱為形式參數 (Formal Parameter),如果有多個參數,則參數之間必須用逗號 (「,」) 分開,參數的型態可以使用變數、陣列、物件或使用者自訂的資料型別。 return:return 用以結束方法,返回呼叫程序;「return < 返回值>」則用以傳回返回值並返回呼叫程序。< 返回值> 的資料型別必須和回傳值資料型別的宣告相同,若傳回值型別為 void,則return 也可以省略。
5.1.3 呼叫靜態方法 呼叫靜態方法中的參數串列, 稱為引數 (Argument), 又稱實參數 (Actual Argument),參數亦可省略 ( 但不可以省略括號)。實參數串列中的資料型態可以是常數、變數、運算式、物件或使用者自訂的資料型態 ( 形式參數不可使用常數和運算式)。實參數將資料傳遞給形式參數,兩者命名可以相同,也可以不相同,但參數的資料型態必須一致。
5.1.4方法返回值 「return < 返回值>」用以傳回返回值並返回呼叫程式,< 返回值> 的資料型別必須和回傳值資料型別的宣告相同,若傳回值型別為 void,則 return 也可以省略。 有些特殊情況必須立刻返回呼叫程式時,可以使用 return 來強迫中止方法的執行。例如方法中有無窮廻圈,可利用 return 直接結束廻圈並立刻返回呼叫程式。
5.2 參數傳遞方式 方法是藉參數串列來傳遞資料,當參數的個數超過一個以上時,參數中間以逗號分開,傳遞參數的方式有傳值呼叫、傳址呼叫、out 和 params。 5.2.1傳值呼叫 宣告方法時,在形式參數前沒有加上 ref、out 等關鍵字,表示參數使用預設的傳遞方式,即為傳值呼叫(call by value), 例如: 執行傳值呼叫方法時,實參數前也不需加任何關鍵字,例如: 在傳值呼叫中,是將實參數複製一份做為形式參數傳送給方法使用,所以實參數與形式參數兩者是獨立的變數,更改形式參數的值並不會影響主程式中實參數的值。
讀者需特別留意,在傳值呼叫中的實參數和形式參數是兩個不同的變數 ( 其名稱可以相同,當然也可以不同),static int Turbo(int Speed) 中的 Speed 形式參數為呼叫方法 Turbo(Speed) 實參數 Speed 的複本,兩者分別指到不同的記憶體位址,當結束方法後,形式參數即自動被釋放,因此不會影響原來實參數的值。
5.2.2 傳址呼叫 在傳址呼叫中,實參數和形式參數共用相同的記憶體位址,所以改變方法中形式參數的值就等於改變主程式中實參數的值。
在傳址呼叫中的實參數和形式參數是相同的變數 ( 其名稱可以不同,當然也可以相同),Turbo(ref int MySpeed) 方法中的 MySpeed 形式參數為呼叫程序 Turbo(refSpeed) 實參數 Speed 的正本,兩者指到相同的記憶體位址,所以改變形式參數MySpeed 即相當於改變實參數Speed 的值。
5.2.3 傳出呼叫 傳出呼叫與傳址呼叫雷同,實參數和形式參數共用相同的記憶體位址,所以改變方法中形式參數的值就等於改變主程式中實參數的值。不同處在於傳出呼叫只能單向接收參數的傳回值而不能傳遞參數值給方法,且主程式的參數可以不必初始化。例如在傳址呼叫中使用未設定初值的實參數時會產生錯誤:
5.2.4 陣列參數傳遞 方法間的參數傳遞,除了常數、變數之外,也可以使用陣列、結構或是物件。使用陣列當參數時,如果是使用陣列中的元素當參數,則可以依一般變數的傳值或傳址來傳遞。 例如 Array 是一個陣列,Array[0] 要使用傳值呼叫,Array[1] 要使用傳址呼叫:
但是如果要將整個陣列當做參數傳遞,則傳遞的是該參數的位址,因此,無論使用傳值呼叫或傳址呼叫,當在方法中修改陣列元素值,都會更改主程式的實參數陣列元素值。不同處在於傳值呼叫方式不允許更改原來陣列的參考,也就是不能將它指向一個新的陣列,而傳址呼叫則可以更改原來陣列的參考。
5.2.5 可變長度的陣列參數 如果需要傳送可變長度的陣列元素做為參數,可在形式參數加上 params 關鍵字,如此會將呼叫方法中的實參數串列做為形式參數陣列的元素值。例如每個班級的人數不同,使用 params 方式將分數傳送給 score 陣列: 使用 params 有幾個限制: 使用 params 的方法不能是「多載」(多載將在下一節說明)。 使用 params 的方法只能使用傳值呼叫,不能使用傳址呼叫或傳出呼叫。 每一個方法傳入的參數只能有一個 params,且必須放在最後一個。
5.3 遞廻 當方法本身又呼叫自已的方法稱為遞廻 (Recursive),撰寫遞廻方法必須注意方法中一定要有結束點,否則程式會形成無窮廻圈而造成錯誤。
5.4 多載 方法的命名允許使用多個相同的名稱,並透過傳遞參數串列或參數的型別來區別不同的方法,稱為多載 (Overloading)。方法多載的好處是可以對功能類似的方法統一命名,以減少建立太多功能類似方法的困擾。 用來區別多載方法的方式有下列兩種:參數串列的參數個數不同及參數的資料型別不同。首先觀察參數型別不同的範例:
5.5 變數存取範圍 Visual C# 變數依其宣告的位置,有多種不同的存取範圍: 5.5.1區塊變數 在 if、switch、for、foreach、while、do⋯while、try⋯catch⋯finally 等程式區塊內宣告的變數稱為區塊變數 (Block Variable),其存取範圍僅在該程式區塊內使用,區塊外則無法存取之。 例如在 for () 區塊宣告的變數 i 和 b,離開廻圈後變數 i 和 b 將被釋放
5.5.2 區域變數 在方法內宣告的變數稱為區域變數 (Local Variable),其存取範圍僅限於此方法中,方法之外無法存取。 例如在 sub2() 方法中使用 sub1() 的變數 a 將產生編譯錯誤:
5.5.3 靜態變數 在類別中宣告的變數, 若變數前面加上 static 關鍵字稱為靜態變數(Static Variable)。靜態變數不能在方法中宣告,當程式執行時,靜態變數是置於全域變數區塊,在記憶中只有儲存一份,且即使多個物件,也共用一份靜態變數記憶體。靜態變數在離開方法後其變數值仍會保留,下次再執行方法時,原來的靜態變數值會繼續使用。 宣告靜態變數時,常會加上存取修飾詞 public、private 或 protected。public 修飾詞表示共用型態,即允許目前應用程式中的所有類別均可存取;private 修飾詞表示只允許在相同類別中存取,protected 修飾詞則表示允許相同類別及其子類別存取。若省略存取修飾詞,系統的預設值為 private。 在相同類別中,直接使用靜態變數名稱即可存取該靜態變數值;若要存取不同類別中的靜態變數,則需以「類別名稱. 靜態變數」來存取。
5.6 文字輸出格式化 通常應用程式為了顯示介面的美觀,當資料以文字方式輸出時,應做適當的格式化處理,讓顯示的資料方式能符合所求。例如:無論金額是否為整數,習慣上顯示金額時會顯示兩位小數。 要將輸出文字格式化,主控台應用程式中可以使用 Console.Write({}) 方法,也可以使用 ToString 方法,但在 Windows 應Form 用程式中則僅可以 ToString 方法。使用Console.Write({}) 方法的語法為:
5.6.1 數字格式化
5.6.2日期時間型別 資料型別中還有一個常用的日期時間型別,因其較為複雜,所以在第二章未提及。 Visual C# 對於日期時間的處理是使用 .NET Framework 內建的 System.DateTime類別,可以設定或取得某一日期與時間的數值,在附錄 A 中會有更詳細的說明。 建立 DataTime 物件的語法主要有兩種,只建立日期的語法為:
5.6.3 日期格式化