優秀的元件設計不僅功能正確,更要在記憶體使用、效能、擴充性上經得起推敲。本文探討三大核心技巧:屬性的 Lazy-Allocate (延遲配置)、事件的 EventHandlerList 優化、Static Helper Object 模式。
public class Class1
{
private MyData _data = new MyData(); // 建構子即配置
public MyData Data => _data;
}
問題:若 MyData 昂貴且不一定被存取,浪費記憶體。
public class Class1
{
private MyData _data;
public MyData Data
{
get
{
if (_data == null) _data = new MyData();
return _data;
}
}
public Class1() { } // 建構子不配置
}
優點:以極小的判斷成本換取未使用時的記憶體節省。ASP.NET Style 屬性即採此模式。
private EventHandler _click;
private EventHandler _doubleClick;
// ... 數百個事件 → 數百個欄位,每個實例皆佔用
public event EventHandler Click { add { _click += value; } remove { _click -= value; } }
using System.ComponentModel;
public class Component1 : Component
{
private static readonly object EventClick = new object();
private static readonly object EventDoubleClick = new object();
public event EventHandler Click
{
add { Events.AddHandler(EventClick, value); }
remove { Events.RemoveHandler(EventClick, value); }
}
public event EventHandler DoubleClick
{
add { Events.AddHandler(EventDoubleClick, value); }
remove { Events.RemoveHandler(EventDoubleClick, value); }
}
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)Events[EventClick];
handler?.Invoke(this, e);
}
}
關鍵點:
Component 基類提供 Events 屬性 (EventHandlerList)。object 鍵值僅佔用一份記憶體,所有實例共用。C# 不允許全域函數/變數,善用 sealed + private constructor + static methods 封裝通用工具函數。
public sealed class DomainHelper
{
private DomainHelper() { } // 防止實例化與繼承
public static string GetCurrentDomainDir() => AppDomain.CurrentDomain.BaseDirectory;
}
// 使用
MessageBox.Show(DomainHelper.GetCurrentDomainDir());
優點:命名空間分組、避免重複程式碼、IntelliSense 易發現、單元測試友善。
這三大技巧體現「以空間換時間」與「集中管理」的設計智慧。延遲配置減少不必要的物件建立,EventHandlerList 解決事件爆炸的記憶體問題,Helper Object 提供乾淨的工具函數組織方式。熟練運用於自訂控制項、元件庫開發,能顯著提升專案品質。