在一般學習程式語言的過程中都會聽到物件導向程式設計(Object-oriented programming, 簡稱OOP)
, 這是一種基於物件(object)概念的開發方式, 能提高程式的可用性, 重複性, 擴展性等等的方式
而在強型別中的 C#, 使用 OOP
開發, 幾乎是不可避免
而要在 C# 中使用 OOP 需要了解一些基本的概念
-
類別(class)
:定義 object 的模板或藍圖
, 描述對象的 field 和 method, 一個 class 通常是由 field 和 method 所組成
-
物件(object)
:物件就是類別(class)的實體化
-
欄位(field)
:定義 class 內的變數(variable)
-
建構函式(Constructor)
:當 object 被創建時自動調用的特殊方法, 用來初始化物件
的狀態
-
方法(method)
:class 中定義的函數, 用來描述 object 的行為
今天使用的舉例 Class(類別)範例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
// Students 類別
internal class Students
{
// 欄位(field)
public string Name;
public int Number;
public int Chinese;
public int English;
public int Math;
// 建構函式(Constructor)
public Students(string name, int number, int chinese, int english, int math)
{
this.Name = name;
this.Number = number;
this.Chinese = chinese;
this.English = english;
this.Math = math;
}
// 方法(method)
private (int, double) Calc()
{
int total = Chinese + English + Math;
double avg = total / 3.0;
return (total, avg);
}
public void ShowInfo()
{
Console.WriteLine($"Name: {Name}, Number: {Number}");
}
public void ShowDetailedInfo()
{
(int totalScore, double avgScore) = Calc();
Console.WriteLine($"Name: {Name}, Number: {Number}, Total Score: {totalScore}, Avg Score: {avgScore:F2}");
}
}
|
類別(Class)
類別(class)簡單來說, 就是物件(object) 的藍圖(blueprint), 以描述學生為例, 需要先有設計圖來確定這個學生會有哪些特性和功能.
類別(Class)就類似這個設計圖, 它會定義未來學生的物件(Object)擁有的欄位(Field) 和方法(Method).
定義類別(class)的語法如下
1
2
3
4
|
internal class classname:
{
statement
}
|
首先會有關鍵字 class, 再來是自定義的 <classname>
, 類別的名稱習慣上會使用 Pasal 命名方式, 即每個單詞的首字母大寫
關鍵字 internal
簡單的說明是:無法被外部不相干的 project 所呼叫, 避免被誤修改操作等動作
範例:
1
2
3
4
5
6
7
8
9
|
// example 1
internal class Students{
}
// example 2
internal class MyChild{
}
|
物件(Object)
物件(object) 就是透過類別(class) 所實際建立的物體, 就是類別(class) 實體化的概念
class 和 object 的關係就像剛剛的學生設計圖和實際的學生
建立物件(object)的語法如下
1
|
object_name = classname();
|
範例:
1
2
|
// example
Students student1 = new Student();
|
範例中的 student1
就是使用 Students class
建立出來的 object
在 C# 中也有簡易的方式用來確認 class 和 object 互相之間的關係, 透過 is
這個 operator, 即可判斷
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
internal class Program
{
static void Main(string[] args)
{
// 建立 Students class object
Students student1 = new Students();
Console.WriteLine(student1 is Students); // 反回 True
Console.WriteLine(student1 is Teachers); // 返回 False
}
}
// Students class
internal class Students
{
}
// Teachers class
internal class Teachers
{
}
|
欄位(Field)
欄位(field) 就是存放 object 的資料
, 也可以說是設定 class 內部的變數(variable)
設定的語法如下:
1
|
object_name.field_name = value;
|
但是因為 C#是強型別的語言, 因此要透過上述方式對 field 進行賦值之前, 需要在 class 中先宣告該 field 和 type
並且在 field 前方也有些修飾符(modifier), 用來控制訪問權限, 這邊只會簡單說明 private 和 public 兩種
-
public: 可以從 class 的外部訪問
-
private: 只能在 class 的內部訪問
範例:
在 class 中先進行宣告
1
2
3
4
5
6
7
|
internal class Students
{
// declare field
public string Name; // 可以從 class 的外部訪問
public int Number;
private int Age; // 只能在 Students class 內部訪問
}
|
創建後賦值
1
2
3
4
5
6
7
|
// create Students class object
Students student1 = new Students();
// Name field
student1.Name = "PawPaw";
// Number field
student1.Number = 1;
// student1.Age = 20; // 這行會導致編譯錯誤,因為 Age 是 private
|
從上面可以看到, 需要先在 class 中宣告 field 和 type, 並在在建立了 object 之後, 才能對 field 進行賦值.
但是這種方式當 field 的數量開始多了之後, 就會顯得非常沒效率, 因此會建議使用待會提到的建構函式(Constructor)
.
而要存取 object field 的值則透過以下語法:
1
2
3
|
Console.WriteLine(student1.Name); // PawPaw
Console.WriteLine(student1.Number); // 1
// Console.WriteLine(student1.Age); // 這行會導致編譯錯誤,因為 Age 是 private
|
使用 private 欄位可以防止外部直接訪問和修改可能的敏感數據.
通常我們會將 field 設為 private, 然後通過 public method 或其他方式來控制對這些 field 的訪問和修改.
建構函式(Constructor)
建構函式(Constructor) 就如上面所說明, 當 object 被創建時自動調用的特殊方法, 用來初始化物件
的狀態.
簡單說就是當你初始化這個 object 的時候就會先強迫輸入所需要的 field value
.
這樣有什麼好處呢?
-
可以增加效率, 不需要一個一個 field 給予 value
-
當 class 中, 有些方法(method) 需要依賴於一些 field 的 value 的時候, 可以避免因為該 field 沒有 value, 而出現錯誤
寫法: 與函數相同, 但是沒有回傳類型, 必須與類別名稱相同
在使用建構函式(Constructor)之前依然需要先進行 field 的宣告
設定的語法如下:
1
2
3
4
5
6
7
8
|
public Students(string name, int number, int chinese, int english, int math)
{
this.Name = name;
this.Number = number;
this.Chinese = chinese;
this.English = english;
this.Math = math;
}
|
在這裡的 this
, 是用來區分 class 的 field 和構建函數(constructor) 的參數(parameter), 所以範例中的意思就是此 class 的 Name
field 等於傳入的 name
parameter
簡單說:
-
this.Name
明確表示為 class 中的 Name field
-
name
(沒有this
)指的是構建函數(constructor) 的參數(parameter)
如下範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Students 類別
public class Students
{
// 欄位(field)
public string Name;
public int Number;
public int Chinese;
public int English;
public int Math;
// 建構函式(Constructor)
public Students(string name, int number, int chinese, int english, int math)
{
this.Name = name;
this.Number = number;
this.Chinese = chinese;
this.English = english;
this.Math = math;
}
}
// 使用 Contructor 創建物件
Students student1 = new Students("John", 1, 80, 75, 90);
|
範例中於建立 student1 物件(Object)的同時, 生成其 field 並且 initial 欄位值(Name, Number, Chinese, English, Math).
在這個例子中無法明顯體會到有沒有 this
的差異, 用下列的舉例可以明顯感受
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
internal class Students
{
// 欄位(field)
public string Name;
public int Number;
// 建構函式(Constructor)
// 使用 this
public Students(string Name, int Number)
{
this.Name = Name;
this.Number = Number;
}
// 不使用 this
public Students(string Name, int Number)
{
Name = Name;
Number = Number;
}
}
|
在這個例子中, 構建函數(constructor)的 parameter 和 field 的名稱剛好一樣:this.Name = Name;
先不說會不會出現 error, 光是在程式上就無法明確的知道是 method 內部的 variable 設定還是要對 class 的 field 賦值
使用 this
的主要原因:
-
清晰性: 明確指出我們在使用 class 的 field,而不是局部變量.
-
避免混淆: 當 parameter 和 field 名相同時(如這個例子), this 可以幫助區分它們.
-
好習慣: 即使參數名不同, 使用 this 也是個好習慣, 使代碼更一致和清晰.
方法(Method)
方法(method) 表示是在 class 中所定義的函數, 可以想成這個 object 所能做的行為
定義方法(Method) 的方式和定義一般的 function 很像, 都是修飾符開頭 -> 返回類型 -> 方法名稱 -> 參數類型 參數名稱
語法如下:
1
2
3
|
modifer return_value method_name(type type_name){
statement
}
|
在 C# 中,我們可以定義不同類型的方法, 以下舉幾個不同的例子
- void method(不返回值的 method):
1
2
3
4
|
public void ShowInfo()
{
Console.WriteLine($"Name: {Name}, Number: {Number}");
}
|
- 返回多個值的 method(使用元組):
1
2
3
4
5
6
|
private (int, double) Calc()
{
int total = Chinese + English + Math;
double avg = total / 3.0;
return (total, avg);
}
|
這個 Calc
method 會計算總分和平均分, 並以 tuple 的形式返回這兩個值. tuple 是 C# 中一種可以包含多個值的 data structure
- 調用其他 method 的 method:
1
2
3
4
5
|
public void ShowDetailedInfo()
{
(int totalScore, double avgScore) = Calc();
Console.WriteLine($"Name: {Name}, Number: {Number}, Total Score: {totalScore}, Avg Score: {avgScore:F2}");
}
|
這個 ShowDetailedInfo
方法調用了 Calc
方法, 並使用其返回值來顯示更詳細的學生信息.
底下使用一個完整的範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
internal class Students
{
// 欄位(field)
public string Name;
public int Number;
public int Chinese;
public int English;
public int Math;
// 建構函式(Constructor)
public Students(string name, int number, int chinese, int english, int math)
{
this.Name = name;
this.Number = number;
this.Chinese = chinese;
this.English = english;
this.Math = math;
}
// private method:計算總分和平均分
private (int, double) Calc()
{
int total = Chinese + English + Math;
double avg = total / 3.0;
return (total, avg);
}
// public method:顯示基本信息
public void ShowInfo()
{
Console.WriteLine($"Name: {Name}, Number: {Number}");
}
// public method:顯示詳細信息
public void ShowDetailedInfo()
{
(int totalScore, double avgScore) = Calc();
Console.WriteLine($"Name: {Name}, Number: {Number}, Total Score: {totalScore}, Avg Score: {avgScore:F2}");
}
}
// 使用示例
Students student1 = new Students("PawPaw", 1, 90, 80, 70);
student1.ShowInfo(); // 輸出:Name: PawPaw, Number: 1
student1.ShowDetailedInfo(); // 輸出:Name: PawPaw, Number: 1, Total Score: 240, Avg Score: 80.00
|
在這個例子中:
-
Calc
是一個 private method, 只能在 class 內部使用. 它計算總分和平均分.
-
ShowInfo
是一個簡單的公 public method,顯示學生的基本信息.
-
ShowDetailedInfo
是另一個 public method, 它調用了 Calc
method 來獲取總分和平均分, 然後顯示更詳細的學生信息.
通過這種方式, 我們可以將複雜的邏輯(如計算分數)封裝在私有方法中, 而將對外展示的功能放在 public method 中. 這種做法提高了代碼的可讀性和可維護性.