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

C# 核心開發四大技巧:介面導向、屬性封裝、委派解耦、初始化順序

     編輯:關於C#

前言

這四個技巧看似基礎,卻是寫出可維護、可擴充、高效能 C# 代碼的基石。本文深入實務場景說明每個技巧的「為什麼」與「怎麼做」。

技巧一:介面導向程式設計

1.1 核心原則

依賴抽象 (介面) 而非具體實作。讓高層模組不依賴低層模組,雙方依賴抽象 (DIP)。

1.2 集合參數:ICollection vs 具體類別


// ❌ 差:鎖定具體類型,無法傳入 List、Array、HashSet、DbQuery 結果
public void LoadItems(List items, ListBox listBox) { ... }

// ✅ 好:接受任何實作 ICollection 的類型
public void LoadItems(ICollection items, ListBox listBox)
{
    foreach (var item in items) listBox.Items.Add(item);
}

// ✅ 更好:IEnumerable (僅需逐一查看),或 IReadOnlyCollection (需 Count)
public void LoadItems(IEnumerable items, ListBox listBox) { ... }

1.3 依賴注入建構函式


// ❌ 緊耦合:內部 new 具體類別,難以測試、替換
public class OrderService
{
    private readonly SqlRepository _repo = new SqlRepository();
}

// ✅ 鬆耦合:依賴介面,由容器/呼叫端提供實作
public class OrderService
{
    private readonly IRepository _repo;
    public OrderService(IRepository repo) => _repo = repo;
}

1.4 介面隔離原則 (ISP)


// ❌ 胖介面:實作類別被迫實作不需要的方法
public interface IUserService
{
    void CreateUser(User u);
    void DeleteUser(int id);
    void SendEmail(string to, string body); // 非用戶管理職責
    void GenerateReport(); // 非用戶管理職責
}

// ✅ 拆分介面
public interface IUserRepository { void Create(User u); void Delete(int id); }
public interface IEmailService { void Send(string to, string body); }
public interface IReportGenerator { Report Generate(); }

技巧二:屬性封裝取代公開欄位

2.1 為什麼不用 public field?

  • 無法加入驗證、通知、延遲載入、序列化控制
  • 二進位相容性:修改欄位為屬性需重新編譯所有呼叫端
  • 介面不可宣告欄位
  • 除錯困難:無法在 setter 設中斷點

2.2 現代屬性寫法


// 自動實作屬性 (C# 3+)
public string Name { get; set; }

// 唯讀屬性 (C# 6+)
public DateTime CreatedAt { get; } = DateTime.UtcNow;

// 初始化後不可變 (C# 9+ init)
public class UserDto
{
    public string Email { get; init; }
    public string Name { get; init; }
}

// 完整封裝:驗證 + 通知
private string _email;
public string Email
{
    get => _email;
    set
    {
        if (value == _email) return;
        if (!value.Contains("@")) throw new ArgumentException("Invalid email");
        _email = value;
        OnPropertyChanged(nameof(Email)); // INotifyPropertyChanged
    }
}

2.3 序列化屬性控制


public class ApiModel
{
    [JsonPropertyName("user_id")] // System.Text.Json
    [XmlAttribute("id")]          // XmlSerializer
    public int Id { get; set; }

    [JsonIgnore] // 不序列化
    [XmlIgnore]
    public string InternalToken { get; set; }

    [JsonInclude] // 私有屬性也序列化
    private string CacheKey { get; set; }
}

技巧三:委派解耦 (事件/回呼/策略模式)

3.1 多點廣播:事件模式


public class KeyboardProcessor
{
    // 事件:多點傳送,鬆耦合
    public event Action LineReceived;

    public void Run()
    {
        while (true)
        {
            string line = Console.ReadLine();
            if (string.IsNullOrEmpty(line)) break;
            
            // 執行緒安全觸發
            LineReceived?.Invoke(line);
        }
    }
}

// 訂閱者
var processor = new KeyboardProcessor();
processor.LineReceived += line => Console.WriteLine($"Echo: {line}");
processor.LineReceived += line => File.AppendAllLines("log.txt", new[] { line });
processor.Run();

3.2 策略模式:注入演算法


public interface IDiscountStrategy
{
    decimal Calculate(Order order);
}

public class OrderService
{
    private readonly IDiscountStrategy _strategy;
    public OrderService(IDiscountStrategy strategy) => _strategy = strategy;

    public decimal GetFinalPrice(Order order) => order.Total - _strategy.Calculate(order);
}

// 具體策略
public class VipDiscount : IDiscountStrategy { public decimal Calculate(Order o) => o.Total * 0.1m; }
public class SeasonalDiscount : IDiscountStrategy { public decimal Calculate(Order o) => DateTime.Now.Month == 12 ? 50 : 0; }

// 使用
var service = new OrderService(new VipDiscount());
// 或動態切換
service = new OrderService(new SeasonalDiscount());

3.3 Func/Action 簡化委派宣告


// 參數化行為
public void ProcessData(IEnumerable data, Func filter, Action handler)
{
    foreach (var item in data)
        if (filter(item)) handler(item);
}

// 呼叫
ProcessData(numbers, n => n % 2 == 0, n => Console.WriteLine(n * 2));

技巧四:掌握初始化順序

4.1 執行順序鐵律

  1. 衍生類別靜態欄位初始化 / 靜態建構函式
  2. 基底類別靜態欄位初始化 / 靜態建構函式
  3. 衍生類別例項欄位初始化運算式
  4. 基底類別例項欄位初始化運算式
  5. 基底類別建構函式本體
  6. 衍生類別建構函式本體

4.2 危險範例:基底建構函式使用衍生欄位


public class Base
{
    public Base() { Initialize(); } // 呼叫虛擬方法
    protected virtual void Initialize() { }
}

public class Derived : Base
{
    private readonly List _items = new(); // 3. 衍生欄位初始化
    protected override void Initialize() 
    {
        _items.Add("test"); // 5. 基底建構函式中呼叫,此時 _items 尚未初始化!
    }
}
// 結果:NullReferenceException 在 _items.Add

4.3 安全模式


public class Base
{
    public Base() { } // 不呼叫虛擬方法
    // 提供非虛擬初始化方法供衍生類別在建構函式末尾呼叫
    protected void InitializeCore() { /* 共用邏輯 */ }
}

public class Derived : Base
{
    private readonly List _items = new();
    public Derived()
    {
        // 衍生建構函式本體執行時,所有欄位已初始化完成
        _items.Add("safe"); 
        InitializeCore();
    }
}

4.4 靜態建構函式觸發時機

  • 第一次存取靜態成員 (欄位/屬性/方法)
  • 第一次建立例項
  • 執行緒安全,僅執行一次
  • 適合複雜靜態資源初始化 (載入原生 DLL、建立單例、解析配置)

總結對照表

技巧核心關鍵字違反後果現代 C# 支援
介面導向interface, DI, ISP緊耦合、難測試、難替換record, primary constructor, required
屬性封裝get/set/init, INotifyPropertyChanged脆弱、無驗證、序列化失控init, required, property patterns
委派解耦event, Func/Action, Strategy硬編碼邏輯、單一職責違反pattern matching, delegate inference
初始化順序field init, ctor chain, static ctorNullReference、資源洩漏、行為異常primary constructor, init accessor

這四個技巧貫穿 C# 程式設計的始終。熟練運用能寫出結構清晰、易於測試、擴充彈性、執行效能佳的專業級代碼。

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