C#入門指南: 一文快速入門C#_4(類別篇)

C#入門指南: 一文快速入門C#_4(類別篇)

更新於 發佈於 閱讀時間約 29 分鐘

Class類別觀念

  • 類別(Class) 是一種用來描述物件(Object)特徵與行為的藍圖或模板。
  • 物件則是依據類別建立的實例(Instance)。

換句話說,類別就像「設計圖」,而物件是根據設計圖打造出來的「實體」。

類別的主要要素:

  • 欄位(Field):用來儲存資料或物件狀態的變數。
  • 屬性(Property):為欄位提供封裝,並允許在存取時執行邏輯(如驗證或計算)。
  • 方法(Method):定義物件的行為與功能,類似於函式,用於執行一個明確的動作或演算。
  • 建構函式(Constructor):當物件被建立時,會自動被呼叫,用來初始化物件。
  • 解構函式(Destructor)(比較少用) :物件被回收時自動執行的程式碼區塊,通常不常手動實作,在 .NET 中交由垃圾回收(Garbage Collector)處理。

簡單範例

以下是一個最簡單的類別範例:

public class Person
{
// 欄位(Field)
private string name;
private int age;

// 屬性(Property)
public string Name
{
get { return name; }
set { name = value; }
}

public int Age
{
get { return age; }
set
{
if (value >= 0)
age = value;
}
}

// 建構函式(Constructor)
public Person(string name, int age)
{
this.name = name;
this.age = age;
}

// 方法(Method)
public void Introduce()
{
Console.WriteLine($"Hello, my name is {name}, and I'm {age} years old.");
}
}
  • public class Person:使用 public 表示此類別可以被其他程式碼存取。類別名稱為 Person
  • private string name;private int age;:私有欄位,只能在此類別內被使用。
  • 屬性 NameAge:用來封裝欄位,常用的好處是可以在 getset 做額外的檢查或運算。
  • 建構函式 Person(string name, int age):用來在建立物件時,初始化 nameage
  • 方法 Introduce():類別定義的行為,這裡只是單純地印出訊息。

接下來,該如何建立物件?以下示範:

class Program
{
static void Main(string[] args)
{
// 使用建構函式建立 Person 物件
Person person1 = new Person("Alice", 25);

// 透過屬性存取與設定欄位
person1.Name = "Alice Chen";
person1.Age = 30;

// 呼叫方法
person1.Introduce();
}
}

輸出結果:

Hello, my name is Alice Chen, and I'm 30 years old.

C# 的存取修飾子

C# 類別宣告的成員變數或方法可以使用private、public、protected、internal、protected internal幾種修飾子指定成員的存取階級,其說明如下:

  • private:成員變數或方法只能在類別本身呼叫或存取,如果沒有使用修飾子,預設是private
  • public:成員變數或方法是此類別建立物件對外的使用介面,任何程式碼都可存取。
  • protected:僅能在同一個類別或其子類別(繼承類別)中存取。
  • internal:在相同 C# 專案的程式檔案可以呼叫或存取,但不包含其它專案。
  • protected internal : 在相同 C# 專案的程式檔案可以呼叫或存取,也能和其它專案繼承此類別的子類別來呼叫和存取。

實務上,主要是使用privatepublicprotected 三種存取修飾子來控制類別成員的存取,例如,類別對外的使用介面宣告成public,需要隱藏的資料或只供類別本身呼叫的方法(工具方法)則宣告成private

屬性的進階用法

唯讀屬性(Read-Only Property)

如果只有 get 存取器,沒有 set 存取器,則該屬性是唯讀的。

public class Person
{
private string name = "Unknown";

public string Name
{
get { return name; }
}
}

使用時只能讀取,不能寫入:

Person person = new Person();
Console.WriteLine(person.Name); // 可以讀取
person.Name = "Alice"; // 編譯錯誤,因為沒有 set 存取器

唯寫屬性(Write-Only Property)

如果只有 set 存取器,沒有 get 存取器,則該屬性是唯寫的。

public class Person
{
private string name;

public string Name
{
set { name = value; }
}
}

使用時只能寫入,不能讀取:

Person person = new Person();
person.Name = "Alice"; // 可以寫入
Console.WriteLine(person.Name); // 編譯錯誤,因為沒有 get 存取器

自動屬性(Automatic Property)

如果屬性的 get 和 set 存取器沒有額外的邏輯,可以使用自動屬性,編譯器會自行實作屬性的getset程式區塊

public class Person
{
public string Name { get; set; } // 自動實作屬性
}

上面程式碼中,Name屬性只有getset,沒有程式碼區塊,C#編譯器會自動宣告private欄位來實作屬性。

使用方式與普通屬性相同:

Person person = new Person();
person.Name = "Alice";
Console.WriteLine(person.Name);

屬性初始化

你可以在宣告屬性時直接初始化:

public class Person
{
public string Name { get; set; } = "Unknown";
}

最常見的情況下:

  • 欄位通常標記為 private
  • 提供 public 屬性或方法進行間接操作。

建構函式(Constructor)與多載(Overloading)

  • 與類別同名,沒有回傳值。
  • 物件建立時會自動被呼叫,可用來初始化欄位或執行必須的動作。
public class Person
{
public string Name { get; set; }
public int Age { get; set; }

// 預設建構函式(沒有參數)
public Person()
{
Name = "Unknown";
Age = 0;
}

// 有參數的建構函式
public Person(string name, int age)
{
Name = name;
Age = age;
}
}

建構函式多載(Overloading)可以定義多個同名建構函式,只要參數數量或型別不同即可。呼叫哪個建構函式取決於傳入的參數形態。

Person p1 = new Person();            // 呼叫無參數建構函式
Person p2 = new Person("Bob", 28); // 呼叫有參數建構函式

繼承(Inheritance)

繼承讓我們可以基於現有的類別延伸出新的類別,使我們能夠重複使用並擴充程式碼。繼承的使用場景為is-a關係,例如,狗是一個動物。基本用法如下:

public class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}

public class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name} is barking.");
}
}
  • Dog : Animal 表示 Dog 類別繼承自 Animal 類別,Dog 便擁有 Animal 的屬性與方法(NameEat())。
  • 可以在 Dog 內再新增專屬於 Dog 的方法或屬性,例如 Bark()

使用範例:

Dog dog = new Dog();
dog.Name = "Lucky";
dog.Eat(); // 繼承自 Animal
dog.Bark(); // Dog 自身方法

關於繼承的建構子呼叫,當衍生類別的物件被建立時,建構子的呼叫順序如下:

  1. 基類的建構子:先呼叫基類的建構子。
  2. 衍生類別的建構子:然後呼叫衍生類別的建構子。

如果基類有一個無參數的建構子(預設建構子),並且衍生類別沒有顯式呼叫基類的建構子,則編譯器會自動呼叫基類的無參數建構子。

public class Animal
{
public Animal()
{
Console.WriteLine("Animal constructor called.");
}
}

public class Dog : Animal
{
public Dog()
{
Console.WriteLine("Dog constructor called.");
}
}

class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
}
}

輸出:

Animal constructor called.
Dog constructor called.
  • Dog 類別繼承自 Animal 類別。
  • 當 Dog 的物件被建立時,會先呼叫 Animal 的建構子,然後呼叫 Dog 的建構子。

如果基類沒有無參數的建構子,或者你想呼叫基類的特定建構子,可以使用 base 關鍵字來顯式呼叫基類的建構子。

public class Animal
{
private string name;

public Animal(string name)
{
this.name = name;
Console.WriteLine($"Animal constructor called with name: {name}");
}
}

public class Dog : Animal
{
public Dog(string name) : base(name) // 顯式呼叫基類的建構子
{
Console.WriteLine("Dog constructor called.");
}
}

class Program
{
static void Main(string[] args)
{
Dog dog = new Dog("Buddy");
}
}

輸出:

Animal constructor called with name: Buddy
Dog constructor called.

多型

多型指的是相同的方法名稱,在不同類別中可以有不同實作。C# 透過關鍵字 virtualoverride 來實現方法的覆寫。

public class Animal
{
public string Name { get; set; }

// 將此方法標示為 virtual,使子類別可覆寫
public virtual void MakeSound()
{
Console.WriteLine("Some generic animal sound");
}
}

public class Dog : Animal
{
// 使用 override 覆寫父類別的 MakeSound 方法
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}

public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("Meow!");
}
}

當你呼叫 MakeSound() 時,會根據物件實際型別去執行相對應的方法:

Animal myAnimal = new Animal();
myAnimal.MakeSound(); // 輸出:Some generic animal sound

Animal myDog = new Dog();
myDog.MakeSound(); // 輸出:Woof!

Animal myCat = new Cat();
myCat.MakeSound(); // 輸出:Meow!

你可以宣告一個基類類型的陣列,並在其中存放衍生類別的物件。當你呼叫陣列中物件的方法時,實際執行的是衍生類別的方法。

public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Animal sound");
}
}

public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Bark!");
}
}

public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("Meow!");
}
}

class Program
{
static void Main(string[] args)
{
// 宣告基類類型的陣列
Animal[] animals = new Animal[3];
animals[0] = new Animal();
animals[1] = new Dog();
animals[2] = new Cat();

// 遍歷陣列,呼叫 MakeSound 方法
foreach (Animal animal in animals)
{
animal.MakeSound(); // 實際執行的是衍生類別的方法
}
}
}

輸出:

Animal sound
Bark!
Meow!

你也可以將基類作為函式的參數類型,並傳入衍生類別的物件。在函式中呼叫方法時,實際執行的是衍生類別的方法。

public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Animal sound");
}
}

public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Bark!");
}
}

public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("Meow!");
}
}

class Program
{
static void Main(string[] args)
{
Animal animal = new Animal();
Dog dog = new Dog();
Cat cat = new Cat();

// 傳入不同的物件
MakeAnimalSound(animal); // 輸出:Animal sound
MakeAnimalSound(dog); // 輸出:Bark!
MakeAnimalSound(cat); // 輸出:Meow!
}

// 函式參數為基類類型
static void MakeAnimalSound(Animal animal)
{
animal.MakeSound(); // 實際執行的是衍生類別的方法
}
}

輸出:

Animal sound
Bark!
Meow!

另外,有一關鍵字: newnew 關鍵字用於隱藏(hide)基類的成員,而不是覆寫它。

  • 這意味著衍生類別的物件會呼叫衍生類別的方法,而不是基類的方法。
  • 如果透過基類的參考來呼叫該方法,則會呼叫基類的版本。
public class Animal
{
public void MakeSound() { Console.WriteLine("Animal sound"); }
}

public class Dog : Animal
{
public new void MakeSound() { Console.WriteLine("Bark!"); }
}

使用時:

Animal animal = new Animal();
animal.MakeSound(); // 輸出:Animal sound

Dog dog = new Dog();
dog.MakeSound(); // 輸出:Bark!

Animal animalDog = new Dog();
animalDog.MakeSound(); // 輸出:Animal sound(因為隱藏了基類的方法)

當你在衍生類別中覆寫了基類的方法,但仍然想執行基類的邏輯時,可以在衍生類別的方法中使用 base.方法名稱() 來呼叫基類的版本。或者即使你使用 new 關鍵字隱藏了基類的成員,你仍然可以在衍生類別中使用 base 關鍵字來呼叫基類的版本。

使用 base 的時機:

  • 擴展基類的功能:當你想在衍生類別中擴展基類的方法,而不是完全取代它時。

範例:

public class Vehicle
{
public virtual void Start()
{
Console.WriteLine("Vehicle is starting.");
}
}

public class Car : Vehicle
{
public override void Start()
{
base.Start(); // 呼叫基類的 Start 方法
Console.WriteLine("Car is ready to drive.");
}
}

class Program
{
static void Main(string[] args)
{
Car car = new Car();
car.Start();
}
}

輸出:

Vehicle is starting.
Car is ready to drive.

抽象類別(Abstract Class)

  • 無法直接被實例化,只能被繼承。
  • 可以包含抽象方法(只定義方法簽名、不包含方法實作)和一般已實作的方法。
  • 適合用來定義核心邏輯與基本架構,讓子類別實作細節。
  • 一個類別只能繼承一個抽象類別。
public abstract class Shape
{
public abstract double GetArea(); // 抽象方法,沒有方法體
}

public class Circle : Shape
{
private double radius;
public Circle(double radius)
{
this.radius = radius;
}

public override double GetArea()
{
return Math.PI * radius * radius;
}
}

介面(Interface)

  • 只包含方法、屬性的宣告,沒有任何實作。
  • 與抽象類別最大的不同是:介面不允許定義任何欄位,也不可包含具體方法。
  • 類別可以同時實作多個介面,意即允許一個類別實現多個介面。

多重介面的使用場景

包括:

  • 組合多種行為:例如一個類別可以同時實現 IFlyable 和 ISwimmable,表示它既能飛又能游泳。
  • 不同的類別可以實現相同的介面。
  • 介面讓類別之間的依賴更加鬆散,便於擴展和維護。
public interface IFlyable
{
void Fly();
}

public interface ISwimmable
{
void Swim();
}

public class Duck : IFlyable, ISwimmable
{
public void Fly()
{
Console.WriteLine("Duck is flying.");
}

public void Swim()
{
Console.WriteLine("Duck is swimming.");
}
}
  • Duck 類別實現了 IFlyable 和 ISwimmable 兩個介面。

多重介面的實現細節

  • 必須實現所有介面成員:一個類別實現多個介面時,必須實現所有介面中定義的成員。
  • 解決名稱衝突:如果多個介面中有相同名稱的成員,可以使用顯式介面實現來區分。
public interface ILogger1
{
void Log();
}

public interface ILogger2
{
void Log();
}

public class Logger : ILogger1, ILogger2
{
// 顯式實現 ILogger1 的 Log 方法
void ILogger1.Log()
{
Console.WriteLine("Logger1 is logging.");
}

// 顯式實現 ILogger2 的 Log 方法
void ILogger2.Log()
{
Console.WriteLine("Logger2 is logging.");
}
}

使用時:

Logger logger = new Logger();

((ILogger1)logger).Log(); // 輸出:Logger1 is logging.
((ILogger2)logger).Log(); // 輸出:Logger2 is logging.

靜態類別(Static Class)與靜態成員(Static Members)

靜態類別(Static Class)

  • 無法被實例化。
  • 所有成員都必須是靜態的。
  • 常用於工具或輔助功能,例如 Math 類別。

靜態成員

  • 靜態欄位、靜態屬性或方法,直接跟隨著類別本身存在,而不屬於任何個別物件。
  • 直接用 類別名稱.成員 的方式呼叫。
public static class MathHelper
{
public static int Add(int a, int b)
{
return a + b;
}
}

// 使用方式
int sum = MathHelper.Add(3, 5); // 不需要建立 MathHelper 物件

好,以上就是我濃縮有關C#類別的觀念知識,雖然本來不想在一篇文章放太多內容,讀者可能沒辦法消化,不過我自己本身在學東西或查資料時,最討厭的就是內容分散,讓人很難有效連貫學習,成效自然不好,當然每個人習慣不一樣,我也不能下定論,總而言之,希望這篇對讀者在快速學習C#這門程式語言上,能夠產生幫助。


本頻道持續更新中(內容涵蓋前端程式設計入門、大學必備程式設計入門、電子系專業課程入門、數學微積分題解)如果身旁有相關科系的學生,不妨推薦一下喔~

相信這裡會是家教或線上課程之外,高中、大學生系統性綜合學習的好選擇。

最後感謝您的觀看!

avatar-img
電資鼠 - 您的學習好夥伴
8會員
169內容數
在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
留言
avatar-img
留言分享你的想法!
在 C# 中,當我們說「寫一個函式」時,實際上通常是「撰寫一個方法」。方法是類別或結構中的一部分,主要目的在於封裝可以被重複呼叫的程式邏輯。 本章節主要會從最基本且正確的程式碼架構開始講起,再逐步進入函式一些重要的概念,讓讀者快速學習此知識。
網上影片篇幅過長,教學卻反而無法切入要點,讓讀者有效率的抓到重點。本章將用一篇文章鉅細靡遺地帶領讀者探討條件敘述、陣列、迴圈控制、字串方法這些核心知識。
前言 C#(C-Sharp)是一種由微軟(Microsoft)開發的 現代化、強型別(Strongly Typed)、物件導向(OOP) 的程式語言。它廣泛應用於 桌面應用程式、Web 開發、遊戲開發(Unity)等多種領域。 本教學系列希望帶領你以最少的天數,從零開始精通 C#。
在 C# 中,當我們說「寫一個函式」時,實際上通常是「撰寫一個方法」。方法是類別或結構中的一部分,主要目的在於封裝可以被重複呼叫的程式邏輯。 本章節主要會從最基本且正確的程式碼架構開始講起,再逐步進入函式一些重要的概念,讓讀者快速學習此知識。
網上影片篇幅過長,教學卻反而無法切入要點,讓讀者有效率的抓到重點。本章將用一篇文章鉅細靡遺地帶領讀者探討條件敘述、陣列、迴圈控制、字串方法這些核心知識。
前言 C#(C-Sharp)是一種由微軟(Microsoft)開發的 現代化、強型別(Strongly Typed)、物件導向(OOP) 的程式語言。它廣泛應用於 桌面應用程式、Web 開發、遊戲開發(Unity)等多種領域。 本教學系列希望帶領你以最少的天數,從零開始精通 C#。