首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> C# 入門

C# 類別完整指南:定義、封裝、建構子/解構子、靜態成員與最佳實踐

     編輯:C# 入門

C# 類別完整指南:定義、封裝、建構子/解構子、靜態成員與最佳實踐

類別 是 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 (值比較)

最佳實踐

  • 單一職責:類別只負責一項核心功能。
  • 封裝欄位:永遠用屬性暴露資料,保留驗證彈性。
  • 建構子注入依賴:強制相依性在建構時提供,確保物件有效狀態。
  • 實作 IDisposable:持有非受控資源時必須實作,搭配 using 使用。
  • 慎用靜態狀態:靜態欄位造成全域狀態,難以測試、平行處理衝突。
  • 優先使用 record:資料傳輸物件 (DTO)、值物件首選 record。
  • 命名慣例:PascalCase 類別/方法/屬性,camelCase 區域變數/私有欄位(加底線前綴)。

常見問題 FAQ

Q: 什麼時候需要解構子?

A: 直接持有非受控資源(IntPtr、SafeHandle、COM 物件)時。若只包裝受控資源(實作 IDisposable 的物件),實作 IDisposable 即可,不需解構子。

Q: 靜態建構子例外狀況會怎樣?

A: 若靜態建構子拋出例外,該類別在當前應用程式域將不可用,後續存取拋出 TypeInitializationException。

Q: struct 和 class 的主要差異?

A: struct 為值型別(堆疊配置、複製語意、無繼承、無解構子),class 為參考型別(堆積配置、參考語意、支援繼承、有解構子)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved