Generic Type 的繼承…
摘要提示
- 泛型基底類別: 以 Editor
作為共用基底,讓子類別在繼承時決定型別,實作一致的介面。 - 由泛型轉為具體型別: 基底類別是泛型,但子類別在繼承時指定型別後即為非泛型類別。
- ASP.NET 控制項場景: 針對 string、int、bool、DateTime 等基本型別與自訂型別建立統一輸入介面。
- 抽象屬性 Value: 在 Editor
中定義抽象屬性 Value,子類別負責具體讀寫實作。 - DateEditor 範例: 以 Calendar 配合 Editor
實作日期編輯器,展現簡潔的繼承與覆寫。 - 重用與一致性: 透過共用基底,事件、狀態保存、驗證等功能可一次實作、全面適用。
- 反射與多型: 搭配反射與屬性可動態產生編輯畫面,並將輸入回寫至物件,落實多型。
- 擴充性設計: 任何跨型別通用邏輯(如 OnChange、值記錄)集中於基底類別即可擴散到全體。
- 實務注意: 此技巧偏進階、不常見於教科書,須謹慎設計以避免濫用與維護成本。
- 範例限制: 文中示範為概念性,完整 sample 需依實際專案情境裁剪整合。
全文重點
作者從先前的 Singleton 泛型基底類別經驗出發,延伸至 ASP.NET 專案中的表單輸入控制項設計。面對多種型別(如 string、int、bool、DateTime、TimeSpan 以及自訂型別如 MemberInfo、RoleInfo)需要各自的編輯器控制項,若以傳統方式分別實作,不但重複且難以統一行為。作者主張以泛型基底類別 Editor
此結構帶來多重收益。首先,所有編輯器共享統一介面與行為,可在基底類別中集中實作共用功能,例如:設定值時自動記錄最後輸入(存檔到檔案或資料庫)、統一提供 OnChange 事件、加入通用驗證或轉換邏輯等。其次,因有共同基底且可藉由泛型約束掌握型別,搭配反射與自訂屬性即可針對任意物件動態產生對應的編輯畫面:掃描物件的欄位/屬性與型別,為每個型別產生對應的 Editor 控制項,最後集中收集各 Editor.Value 寫回物件,形成自動化的表單生成與資料回寫流程。若沒有一致的基底類別與型別化的 Value,這種多型組裝幾乎難以實現。
文中提供最小可行概念範例:Editor
段落重點
背景與動機:從 Singleton 泛型延伸到控制項設計
作者先回顧先前以泛型搭配 Singleton 的作法,指出「基底類別可為泛型、子類別繼承時指定型別」的模式雖少見,卻能解決特定設計問題。這次將該觀念延伸到 ASP.NET 控制項開發:希望為各種資料型別打造一致且可重用的輸入編輯器。傳統以 object 一把抓或逐一客製會導致程式碼冗長、維護困難,作者因此尋求更具彈性與可維護性的泛型化方案。
問題情境:多型別資料輸入的繁瑣與不一致
專案需要支援多種基本與自訂型別的輸入控制項。若逐一硬寫 UserControl,短期看似可行,但長期缺乏一致行為與重用性;若統一用 object 處理,則失去型別安全與良好可讀性。核心矛盾在於:每個控制項的輸入型別不同,卻又希望抽取共同邏輯至基底類別。這正是泛型能發揮的點:在不犧牲型別資訊的前提下進行抽象化。
泛型基底類別構想:Editor 與抽象 Value
提出 Editor
範例實作:以 DateEditor 展示簡潔的繼承與覆寫
以 Calendar 建立日期輸入器 DateEditor,繼承 Editor
共用基底帶來的好處:重用、事件、持久化與多型
作者列舉多項立竿見影的收益:1) 在基底類別攔截 set Value,即可實作「記住上次輸入」之類的通用功能,所有編輯器自動具備;2) 統一提供 OnChange 事件,頁面開發者可一致性地訂閱;3) 搭配反射與屬性,能掃描任意物件的成員型別,動態產生對應 Editor,並在提交時收集各 Editor.Value 回寫物件,實現多型化、自動化的表單生成與資料回填;4) 任何通用能力(驗證、轉換、追蹤、Telemetries)都可集中於 Editor
實務考量與結語:進階技巧的邊界
作者坦言完整 sample 不易在短文中涵蓋,實務上往往牽涉屬性標註設計、控制項生命週期、狀態保存策略(檔案/DB)、事件轉接、反射裝配與錯誤處理等面向。此模式屬進階用法,教科書少見,需有良好 OO 與泛型經驗、清楚的邊界與約束,才能避免過度工程或維護成本上升。就架構觀點,此作法提供堅實基礎,讓多型別輸入控制項在型別安全、一致性與重用性間取得平衡,長期有助專案品質與開發效率。
資訊整理
知識架構圖
- 前置知識:
- 物件導向基礎(繼承、抽象、封裝、polymorphism)
- C# 泛型語法與型別參數(class T、泛型屬性/方法)
- ASP.NET Web Forms 基礎(UserControl、.ascx/.cs、Page Life Cycle、ViewState)
- .NET 事件模型與屬性(Event、Attribute)
- 反射(Reflection:取得型別、屬性/欄位資訊)
- 核心概念:
- 泛型基底類別:以 Editor
作為泛型 UserControl,將輸入值抽象為 T Value - 指定型別的非泛型子類:如 DateEditor : Editor
,在繼承當下固化型別 - 共用行為下沉:跨型別共通功能(記錄上次值、統一 OnChange 事件等)集中於 Editor
- 反射 + Attribute + 多型:以物件中屬性型別動態產生對應 Editor,並回填值
- 可擴充的型別編輯器體系:針對 string/int/bool/DateTime/自訂型別建立一致的編輯元件家族
- 泛型基底類別:以 Editor
- 技術依賴:
- Editor
依賴 System.Web.UI.UserControl 提供 WebForms 控制項基礎 - 各具體 Editor(如 DateEditor)依賴 ASP.NET 控制項(如 asp:Calendar)來呈現/輸入
- 共用事件(OnChange)與狀態保存(記住上次值)依賴基底類別注入切面式邏輯
- 反射流程依賴:Type/PropertyInfo/Attribute → 決定對應 Editor
→ 建立控制項 → 賦值/取值
- Editor
- 應用場景:
- 建立一致的資料編輯元件庫(基本型別與自訂型別)
- 動態表單產生器:根據任意物件自動生成編輯 UI 並自動回寫
- 跨頁面複用的輸入邏輯(記住上次輸入、統一驗證、統一事件)
- 需要快速擴展新型別輸入的專案(加新 Editor 即可掛入生態系)
學習路徑建議
- 入門者路徑:
- 了解 C# 泛型與類別繼承的基礎語法
- 實作最小可行 Editor
:定義抽象屬性 T Value - 建立一個 DateEditor : Editor
,用 asp:Calendar 實作 Value get/set - 在 .aspx 中引用並設定 value,理解基本使用流程
- 進階者路徑:
- 在 Editor
加入共用行為:OnChange 事件、狀態保存(例如以 ViewState、Session、檔案或資料庫) - 擴展多個具體 Editor:StringEditor、IntEditor、BoolEditor 等
- 將驗證(Validation)、預設值、格式化等收斂在基底類或以 Attribute 驅動
- 處理進階議題:Nullable 型別、文化區設定/日期格式、例外處理與使用者回饋
- 在 Editor
- 實戰路徑:
- 以反射掃描任意物件的屬性型別,對應到合適的 Editor
並動態加入頁面 - 設計 Attribute(例如 [Editor(typeof(DateEditor))]、[Display(Name=…)])決定 UI 呈現與編輯策略
- 實作回填:在表單提交時從各 Editor 取回值並寫回原物件
- 抽象出工廠/映射機制(Type → Editor 類別)與組態,讓新增型別編輯器零侵入接軌
- 以反射掃描任意物件的屬性型別,對應到合適的 Editor
關鍵要點清單
- 泛型基底類別 Editor
: 以 T Value 抽象輸入/輸出,統一各型別編輯器的介面 (優先級: 高) - 非泛型子類固化型別: 透過 DateEditor : Editor
將泛型在繼承時定型,便於實際使用 (優先級: 高) - 共用行為下沉: 在 Editor
集中實作記住上次輸入、統一事件、共用驗證等 (優先級: 高) - OnChange 統一事件: 在基底類定義與觸發變更事件,讓所有 Editor 一致對外 (優先級: 中)
- 反射產生 UI: 以反射讀取物件屬性型別,動態建立對應 Editor,快速生成編輯畫面 (優先級: 高)
- Attribute 驅動: 以自訂屬性標註編輯策略與顯示資訊,提升彈性與可讀性 (優先級: 中)
- 值的持久化策略: 設計將 Value set 時的資料保存至 ViewState/Session/檔案/DB 的機制 (優先級: 中)
- 型別對應映射: 建立 Type → Editor 類別或工廠對應,降低反射生成的耦合 (優先級: 中)
- 驗證與錯誤處理: 在基底類或統一管道處理資料驗證、例外、使用者提示 (優先級: 高)
- ASP.NET 生命周期與 ViewState: 理解 Init/Load/PreRender 對動態控制項與資料回填的影響 (優先級: 高)
- 文化區與格式化: 日期/數字的文化區處理與格式化策略(尤其 DateTime/decimal) (優先級: 中)
- Nullable 與預設值: 支援 Nullable
與合理的預設/空值行為 (優先級: 中) - 多型與可測試性: 以多型封裝行為並為 Editor 建立單元測試/整合測試 (優先級: 中)
- 可擴充性與重用性: 透過基底類與映射,新增型別編輯器時幾乎零變更既有流程 (優先級: 高)
- 效能與維護性: 控制反射使用範圍、快取型別資訊,保持可維護的架構 (優先級: 低)