# **Delphi 命名規範與風格指南 (Naming Conventions)** ## **1. 大小寫敏感度 (Case Sensitivity)** 在探討具體規範前,我們必須先釐清 Delphi 編譯器的特性: - **Delphi 是「大小寫不敏感」的 (Case-Insensitive):** 對 Delphi 編譯器而言,CaseID、caseid、CASEID 甚至 cAsEiD 都是**完全相同**的變數。這與 C++, C#, Java, JavaScript (這些是 Case-sensitive) 有著根本上的不同。 - **為什麼還需要規範?** 既然編譯器不在乎,為什麼大家還是很嚴格遵守大小寫?因為**「人」在乎**。統一的大小寫規範(通常是 PascalCase)能極大提升程式碼的可讀性。 - **何時大小寫「絕對」重要?** 當 Delphi 與外部世界溝通時!例如: 1. 呼叫 C/C++ 寫的 DLL 函數(如 Windows API)。 2. 處理 JSON/XML 資料解析時。 3. 將 ActiveX/OCX 元件提供給網頁端的 JavaScript 呼叫時(這也是為什麼你在 _TLB.pas 裡會看到像 caseno 這種全小寫的屬性,因為它是為了迎合 JS/Web 的習慣)。 ## **2. 常見的程式命名風格 (Casing Styles)** 了解以下三種風格,有助於我們理解 Delphi 的選擇: 1. **PascalCase (帕斯卡命名法)**:每個單字的首字母都大寫。 - *範例*:CalculateTotal, UserName, CaseID - **Delphi 的最愛**:Delphi 絕大多數的命名都基於這個風格。 1. **camelCase (駱駝命名法)**:第一個單字全小寫,後續單字首字母大寫。 - *範例*:calculateTotal, userName, caseId - **Delphi 的應用**:偶爾用於區域變數(Local Variables),但在傳統 Delphi 中不如 Java/C# 常見。 1. **snake_case (蛇形命名法)**:全小寫,單字間用底線 _ 分隔。 - *範例*:calculate_total, user_name, case_id - **Delphi 的應用**:**極少使用**。通常只出現在早期的舊程式碼,或是為了與 C 語言庫(如 SQLite, LibVLC)保持一致時才會使用。 ## **3. Delphi 核心命名規範 (前綴字慣例)** Delphi 最具特色的就是使用**單一字母前綴**來標示該元素的「種類」或「作用域」。 | **元素類型 (Type)** | **前綴** | **命名風格** | **範例與說明** | | --- | --- | --- | --- | | **類別 (Class/Type)** | **T** | PascalCase | TForm, TCustomer *(T 代表 Type,所有類別與自訂型別皆以此開頭)* | | **介面 (Interface)** | **I** | PascalCase | IUnknown, IScanner *(I 代表 Interface)* | | **例外 (Exception)** | **E** | PascalCase | EOutOfMemory, EFileNotFound *(E 代表 Exception)* | | **指標 (Pointer)** | **P** | PascalCase | PChar, PInteger *(P 代表 Pointer)* | | **私有欄位 (Field)** | **F** | PascalCase | FCaseID, FWidth *(F 代表 Field,僅存在於類別的 private/protected 區段)* | | **屬性 (Property)** | **無** | PascalCase | CaseID, Width *(對外公開的屬性,通常用來讀寫對應的 F 變數)* | | **方法參數 (Parameter)** | **A** | PascalCase | AOwner, ACaseID *(A 代表 Argument,用以避免與內部 Field 撞名)* | ## **4. 變數與常數命名** - **區域變數 (Local Variables)**: - 通常使用 **PascalCase**,不加前綴。例如:ImageStream, TotalCount。 - 迴圈計數器習慣使用大寫字母:I, J, K。 - **全域變數 (Global Variables)**: - 盡量避免使用。若必須使用,部分開發者會加上 G 前綴(如 GSystemStatus)。 - **常數 (Constants)**: - 現代 Delphi 傾向直接使用 PascalCase 配合列舉。部分開發者使用 c 前綴(如 cMaxRetries)。 ## **5. 列舉型別 (Enumerations) 的特殊規範** Delphi 對列舉型別有非常優雅的規範:**型別以 T 開頭,列舉值以該型別的 2~3 個字母縮寫作為小寫前綴。** - *範例*: type TTransMode = (tsHttp, tsFtp, tsNone); TFormAlign = (alNone, alTop, alBottom, alLeft, alRight, alClient); ## **6. 檔案與單元 (File & Unit) 命名** 在 Delphi 中,檔案名稱(.pas)與程式碼內宣告的單元名稱(unit XXX;)**必須完全一致**。 - **基本規則**:使用 **PascalCase**,避免使用空白與特殊字元。 - **視覺化窗體 (Forms)**:單元檔名通常結尾加上 Frm、Form 或 UI。 - **資料模組 (DataModules)**:單元檔名通常結尾加上 DM。 ## **7. 檔案命名後綴與副檔名解析 (File Extensions & Suffixes)** 在 Delphi 的專案架構中,除了單元名稱外,副檔名與特定的檔名後綴也承載了重要的架構意義。 ### **7.1 檔名後綴 _TLB** 當你開發或匯入 COM、ActiveX 或 Automation Server 時,Delphi IDE 會自動生成以 _TLB 結尾的檔案(例如 CB_IMGPSScan_TLB.pas)。 - **意義**:TLB 是 **Type Library (類型庫)** 的縮寫。 - **作用**:Type Library 本身是一個二進位檔案,用來跨語言描述 COM 元件的介面。Delphi 為了讓 Object Pascal 能呼叫這些介面,會將其反編譯成 .pas 程式碼,並自動加上 _TLB 後綴。 - **⚠️ 核心規範**:**絕對不要手動修改 _TLB.pas 檔案的內容!** 只要你在 IDE 中重新整理 Type Library,這個檔案就會被完全覆蓋重寫。若要實作功能,應寫在對應的 _Imp.pas 或其他單元中。 ### **7.2 常見的 Delphi 副檔名** 以下是 Delphi 專案中常見的副檔名及其具體用途: | **副檔名** | **類型** | **說明** | | --- | --- | --- | | **.pas** | 原始碼 (Source) | **Pascal Source File**。最常見的程式碼檔案(單元/Unit),包含介面宣告 (interface) 與實作邏輯 (implementation)。 | | **.dpr** | 專案檔 (Project) | **Delphi Project**。專案的主進入點,定義這是一個執行檔 (program) 還是程式庫 (library),並包含專案的啟動邏輯與引入單元列表。 | | **.dfm** | 介面檔 (Form) | **Delphi Form**。儲存視覺化窗體 (Form) 或資料模組 (DataModule) 上所有元件的屬性與佈局設定。一定與同名的 .pas 檔成對出現。 | | **.dcu** | 編譯檔 (Compiled) | **Delphi Compiled Unit**。.pas 檔案成功編譯後產生的二進位結果。最終連結器 (Linker) 會將這些 .dcu 打包成 EXE 或 DLL。 | | **.res** | 資源檔 (Resource) | **Compiled Resource File**。二進位資源檔,包含應用程式圖示 (Icon)、版本資訊或夾帶的檔案。通常在 .dpr 中用 {$R *.res} 編譯指令引入。 | | **.tlb** | 類型庫 (Type Lib) | **Type Library**。微軟 COM 標準的二進位檔案,用來描述 ActiveX 元件對外公開的介面、方法與屬性,供其他語言(如 C++, JS)參考呼叫。 | | **.ridl** | 介面定義 (RIDL) | **Restricted Interface Definition Language**。較新版 Delphi 用來取代舊式二進位 .tlb 的純文字介面定義檔。開發者可以透過文字或 IDE 編輯它,編譯時會自動生成對應的 .tlb 與 _TLB.pas。 | | **.ocx** | 控件擴充檔 | **OLE Control Extension**。本質上是一個特殊格式的 DLL(動態連結函式庫),內部包含了 ActiveX 控件。Windows 系統可以透過 regsvr32 註冊它,讓 IE 瀏覽器或其他應用程式嵌入使用。 | ## **8. Delphi 架構與現代語言概念對應 (Architecture Mapping)** 對於習慣 C#、Java、Python 或 JavaScript 的開發者,了解 Delphi 專屬的結構名詞如何對應到現代語言是非常重要的。 ### **8.1 Namespace (命名空間)** - **現代語言對應**:等同於 C# 的 namespace、Java 的 package,或是 C++ 的 namespace,用來組織程式碼並避免名稱衝突。 - **Delphi 的對應**: - **早期 Delphi (如 Delphi 7/2007)**:沒有明確的 Namespace 關鍵字,**unit (單元) 本身就充當了扁平化的命名空間**。為避免撞名,開發者強烈依賴「前綴字」(例如 Indy 網路套件都以 Id 開頭,如 IdHTTP;Envision 影像套件以 En 開頭,如 EnScan)。 - **現代 Delphi (XE2 以後)**:正式引入了 **Dotted Unit Names (點綴命名)** 作為 Namespace 的支援。例如原先的 SysUtils.pas 變成了 System.SysUtils.pas,Forms.pas 變成了 Vcl.Forms.pas。 ### **8.2 Class (類別)** - **現代語言對應**:等同於 C# / Java / TS 的 class。 - **Delphi 的對應**:同樣使用 class 關鍵字,但在 Delphi 中必須宣告於 type 區塊之下。如前文所述,類別名稱慣例上**必須以大寫 T 開頭**(例如 TMainForm)。實體化時,Delphi 是呼叫建構子方法(如 TMyClass.Create),而不是使用 new 關鍵字。 ### **8.3 Unit (單元, .pas)** - **現代語言對應**:等同於 ES6 的 **Module (.js/.ts)**、Python 的 **Module (.py)**,或是 C/C++ 中 .h (標頭檔) 與 .cpp (原始檔) 的綜合體。 - **Delphi 的對應**:unit 是 Delphi 程式碼封裝的最核心基礎。一個完整的 unit 會被劃分為兩個主要區塊: - **interface (介面區)**:等同於對外輸出的 API 或 Header,這裡宣告的型別與函式可透過 uses 關鍵字被其他檔案呼叫。 - **implementation (實作區)**:等同於內部的私有邏輯實作。在這裡宣告的變數或函式,對外部檔案是完全隱藏的。 ### **8.4 Library (程式庫, .dpr)** - **現代語言對應**:等同於 C# 的 **Class Library 專案**、Node.js 的原生 C++ 附加元件,或 C/C++ 的 **Shared Library / 動態連結檔**。 - **Delphi 的對應**:在專案原始檔中(.dpr),如果開頭宣告為 library(而非一般視窗程式的 program),代表它的編譯目標是一個不具獨立執行程序的主體,通常會編譯為 **.dll** 或 **.ocx**。這類專案主要透過 exports 關鍵字,將內部的函式暴露給作業系統或其他語言的程式(如 C++ 或網頁瀏覽器)來呼叫。 ## **9 Compiler Directive** 在 Delphi (Object Pascal) 中,`{ }` 符號的意義取決於緊跟在 `{` 後面的第一個字元。這是一個非常基礎但關鍵的語法,讓我們來拆解你的疑問: --- ### 9.1 `{ }` 符號的基本意義:註解 (Comments) 在最基本的情況下,`{ }` 是 **「區塊註解」**。編譯器會完全忽略裡面的內容。 * **`{ TCB_IMGPSScanX }`**:這是一段 **註解**。 * **作用**:通常開發者寫這行是為了告訴讀程式碼的人:「接下來這一段程式碼是屬於 `TCB_IMGPSScanX` 類別的實作」。它對程式執行**沒有任何影響**。 * **`TCB_IMGPSScanX`**:這是一段 **程式碼 (識別碼)**。 * **作用**:編譯器會去尋找名為 `TCB_IMGPSScanX` 的類別、型別或變數。如果沒定義,編譯就會報錯。 --- ### 9.2 `{$ }` 符號的進階意義:編譯指令 (Compiler Directives) 當 `{` 後面緊跟著 **`$`** 字元時,它就從「註解」變成了 **「編譯指令」**。這不是給人看的,而是**給編譯器下的指令**。 #### 關於 `{$I filename}` (Include 指令) 你看到的 `{$I ...}` 是 **Include Directive**。 * **作用**:它的功能就像是編譯器的「複製貼上」工具。它告訴編譯器:「在編譯這行時,請先去把 `CB_IMGPSScanImp_UI.pas` 檔案裡的文字**原封不動地抓過來,塞到這個位置**,然後再繼續往下編譯」。 * **目的**:這通常用來處理非常巨大的程式碼檔案。就像你之前的 `CB_IMGPSScanImp.pas` 檔案太長了,開發者把它拆成小檔案,最後用這種方式在主檔「匯合」。 --- ### 9.3 解析你的範例語法 你提到的這一段: `{$I CB_IMGPSScanImp_UI.pas}{$I CB_IMGPSScanImp_Scan.pas}...initialization` #### 這是在做什麼? 這既不是定義,也不是宣告,更不是字串。它是一種 **「程式碼組合行為」**。 1. **組合實作內容**:編譯器會依序讀入 `UI.pas`、`Scan.pas`、`Data.pas`、`Utils.pas`。這四個檔案裡放的通常是 `TCB_IMGPSScanX` 的各種 `procedure` 和 `function` 實作。 2. **銜接初始化區段**:當上述所有檔案的內容都被「貼進來」後,程式碼剛好接到了 `initialization` 關鍵字。 #### 語法邏輯如下: ```pascal implementation // 編譯器開始貼上檔案 [貼上 UI.pas 的內容] [貼上 Scan.pas 的內容] [貼上 Data.pas 的內容] [貼上 Utils.pas 的內容] // 貼完後,剛好銜接這支單元的初始化邏輯 (AxCtrl) initialization TActiveFormFactory.Create(...); SetLicenseKey(...); end. ``` ### 總結 * **`{ ... }`** = 註解(編譯器不看)。 * **`{$I ...}`** = 編譯器指令(叫編譯器去別的檔案搬程式碼過來貼上)。 * **為什麼這樣寫?** 這是為了讓主檔保持簡潔。主檔只負責「宣告結構」和「啟動初始化」,而「具體的細節邏輯」則被藏在那些被 Include 的檔案裡。 ## 10. 註解語法與風格慣例 (Comments Style) Delphi 提供三種主要的註解方式,以及一些開發者社群常用的視覺化風格: ### 10.1 單行註解 (`//`) - **用法**:從 `//` 開始到該行結束。 - **視覺強調 (`////`)**: - 你在源碼中看到的 `////` 語法上等同於 `//`。 - **開發者意圖**:通常用於**「標題化」**或**「強力分隔」**。多個斜線能在視覺上形成橫條效果,幫助開發者在快速捲動程式碼時一眼認出關鍵區塊(例如:`//// ***** 預設區 ***** ////`)。 ### 10.2 區塊註解 (`{ }`) - **用法**:被 `{ }` 包圍的所有文字。 - **特點**:常用於長篇說明的標註,或是在調試時暫時關閉一整段程式碼。 - **編譯指令**:若開頭為 `{$`(如 `{$R *.DFM}`),則代表它是給編譯器的指令,而非一般註解。 ### 10.3 替代區塊註解 (`(* *)`) - **用法**:由 `(*` 開始到 `)` 結束。 - **主要用途 (註解嵌套)**:當你想要註解掉一段已經包含 `{ }` 註解的程式碼時,Delphi 規定 `{ }` 不能包在另一對 `{ }` 裡面,此時必須改用 `(* ... *)` 來包裹,才能正確註解。 ### 10.4 文件化註解 (`///` XML Documentation) - **用法**:在方法上方使用連續三個斜線。 - **作用**:現代 Delphi IDE (XE 以後) 會解析這類註解,並在鼠標懸停於方法名上時顯示提示說明(類似 JavaDoc 或 C# XML Doc)。 ### 10.5 分隔線風格示例 在大型檔案(如 `CB_IMGPSScanImp.pas`)中,常用註解來劃分功能界線: ``` // ********************************************************************* // // 這是區塊分隔線風格,常用於自動生成的 TLB 檔 // ********************************************************************* // {-----------------------------------------------------------------------} { 這是另一種常見的手寫分隔線風格 } {-----------------------------------------------------------------------} ```