類別 是 C# 物件導向程式設計的核心建構單元,它是建立物件的藍圖。類別定義了物件的狀態(欄位/屬性)與行為(方法/事件)。本文涵蓋類別定義語法、封裝原則、建構子與解構子、靜態成員、巢狀類別、部分類別等完整主題。
[attributes] [modifiers] class ClassName [: baseClass, interfaces] {
// 欄位
private int _id;
public string Name { get; set; } // 自動實作屬性
// 建構子
public ClassName(int id, string name) {
_id = id; Name = name;
}
// 方法
public void Display() => Console.WriteLine($"{_id}: {Name}");
// 事件
public event EventHandler Changed;
}
存取修飾詞:public、internal、private(預設)、protected、protected internal、private protected。
封裝將資料(欄位)設為 private,透過 public 屬性/方法控制存取:
public class BankAccount {
private decimal _balance; // 隱藏內部狀態
public decimal Balance => _balance; // 唯讀屬性
public void Deposit(decimal amount) {
if (amount <= 0) throw new ArgumentException("金額必須為正數");
_balance += amount;
}
public bool Withdraw(decimal amount) {
if (amount <= 0 || amount > _balance) return false;
_balance -= amount; return true;
}
}
屬性優於欄位:屬性提供驗證、通知、延遲載入、唯讀等彈性,介面不暴露實作細節。
無參數建構子。若類別未定義任何建構子,編譯器自動提供;一旦定義任一建構子,預設建構子不再自動產生。
public class Point {
public int X { get; }
public int Y { get; }
public Point(int x, int y) { X = x; Y = y; } // 唯讀屬性初始化
}
public class Customer {
public string Name { get; }
public string Email { get; }
public int LoyaltyPoints { get; }
public Customer(string name) : this(name, null, 0) {}
public Customer(string name, string email) : this(name, email, 0) {}
public Customer(string name, string email, int points) {
Name = name; Email = email; LoyaltyPoints = points;
}
}
初始化靜態欄位,執行一次,無參數、無存取修飾詞:
public class Config {
public static string ConnectionString { get; private set; }
static Config() {
ConnectionString = LoadFromConfigFile(); // 複雜初始化邏輯
}
}
解構子(~ClassName())為終結器,由 GC 執行期非決定性呼叫,用於釋放非受控資源(檔案控制代碼、資料庫連線、原生記憶體):
public class FileWrapper : IDisposable {
private FileStream _stream;
private bool _disposed;
public FileWrapper(string path) => _stream = File.OpenRead(path);
// 解構子:防禦性清理
~FileWrapper() => Dispose(false);
// IDisposable 模式
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this); // 告訴 GC 不需呼叫解構子
}
protected virtual void Dispose(bool disposing) {
if (_disposed) return;
if (disposing) _stream?.Dispose(); // 釋放受控資源
_stream = null; // 釋放非受控資源
_disposed = true;
}
}
重要:現代 C# 應優先實作 IDisposable / IAsyncDisposable,搭配 using 宣告確定性釋放,解構子僅作為安全網。
static 成員屬於類別本身,而非特定實例:
public class MathUtils {
public const double PI = 3.1415926535; // 編譯期常數
public static readonly double E = Math.E; // 執行期唯讀
private static int _callCount;
public static int CallCount => _callCount;
public static double CircleArea(double r) {
_callCount++;
return PI * r * r;
}
}
// 使用:無需實例
var area = MathUtils.CircleArea(5);
Console.WriteLine(MathUtils.CallCount); // 1
靜態類別:只能包含靜態成員、不可實例化、不可繼承(隱含 sealed):
public static class Extensions {
public static bool IsNullOrEmpty(this string s) => string.IsNullOrEmpty(s);
}
定義在另一個類別內部,可存取外部類別的 private 成員:
public class Outer {
private int _secret = 42;
public class Inner {
public void Reveal(Outer o) => Console.WriteLine(o._secret); // 可存取
}
}
partial class 將類別定義分散在多個檔案,編譯時合併:
// File1.cs
public partial class Person { public string FirstName { get; set; } }
// File2.cs
public partial class Person { public string LastName { get; set; } }
常用於:設計工具產生的程式碼分離、大型類別模組化、多開發者並行開發。
編譯器自動產生的唯讀類別,用於臨時資料投影:
var person = new { Name = "John", Age = 30 };
// 型別名稱編譯器產生,只能在區域變數使用
C# 9+ record 提供不可變參考型別,內建值相等性、with 運算式、解構:
public record Person(string FirstName, string LastName);
var p1 = new Person("John", "Doe");
var p2 = p1 with { FirstName = "Jane" }; // 建立新實例
Console.WriteLine(p1 == p2); // False (值比較)
using 使用。A: 直接持有非受控資源(IntPtr、SafeHandle、COM 物件)時。若只包裝受控資源(實作 IDisposable 的物件),實作 IDisposable 即可,不需解構子。
A: 若靜態建構子拋出例外,該類別在當前應用程式域將不可用,後續存取拋出 TypeInitializationException。
A: struct 為值型別(堆疊配置、複製語意、無繼承、無解構子),class 為參考型別(堆積配置、參考語意、支援繼承、有解構子)。