1. 程式人生 > >《.NET 設計規範》第 5 章:成員設計

《.NET 設計規範》第 5 章:成員設計

支持 派生 精度 tex 邏輯 最好 功能 一個 覆蓋

《.NET 設計規範》第 5 章:成員設計

5.1 成員設計的通用規範

  要盡量用描述性的參數名來說明在較短的重載中使用的默認值。

  避免在重載中隨意地改變參數的名字。如果兩個重載中的某個參數表示相同的輸入,那麽該參數的名字應該相同。

  避免使重載成員的參數順序不一致。在所有的重載中,同名參數應該出現在相同的位置。

  要把最長的重載成員定義成重載成員中唯一的虛成員。

  不要用 ref 或 out 修飾符來對成員進行重載。

  不要定義這樣的重載:位於同一個位置的參數有相似的類型但卻有不同的語義。

  要允許在傳遞參數時將可選參數設為 null。

  要優先使用成員重載,而不是定義有默認參數的成員。

  顯式地實現接口成員。

  避免顯示地實現接口成員 - 如果沒有很強的理由。

  考慮顯式地實現接口成員 - 如果希望接口成員只能通過該接口來調用。

  考慮通過顯式地實現接口成員的方式來模擬變體。

  考慮在需要隱藏一個成員並增加另一個名字更合適的等價成員時,顯式地實現接口成員。

  不要把接口成員的顯示實現當做安全壁壘。

  要為顯式實現的接口成員提供具有相同功能的受保護的虛成員 - 如果希望讓派生類對該功能進行定制。

  考慮使用屬性 - 如果該成員表示類型的一種邏輯屬性。

  要使用屬性而不要使用方法 - 如果屬性的值儲存在進程內存中,而且提供屬性的目的僅僅是為了訪問該值。

  要在下列情況中時使用方法而不要使用屬性:

    該操作比字段訪問要慢幾個數量級;

    該操作是一個轉換操作,如:object.ToString() 方法;

    該操作在每次調用時都返回不同的結果,即使傳入的參數不變。如:Guid.NewGuid 方法在每次都返回不同的值;

    該操作有嚴重的、顯而易見的副作用;

    該操作返回內部狀態的一個副本(這不包括那些在棧上返回的值類型對象的副本);

    該操作返回一個數組。

5.2 屬性的設計

  要創建只讀屬性 - 如果調用方不應該改變屬性的值。

  不要提供只寫屬性,也不要讓 setter 的可訪問性比 getter 更廣。

  要為所有的屬性提供合理的默認值,這樣可以確保默認值不會導致安全漏洞或效率低下的代碼。

  要允許用戶以任何順序來設屬性的值,即使這可能會使對象在短時間內處於無效狀態。

  要保留屬性原來的值,如果屬性的 setter 拋出異常。

  避免在屬性的 getter 中拋出異常。

  考慮通過索引器的方式讓用戶訪問存儲在呢不數組中的數據。

  考慮為代表元素集合的類型提供索引器。

  避免使用有一個以上參數的索引屬性。

  避免用 System.Int32、System.Int64、System.String、System.Object、枚舉或泛型參數之外的類型來作索引器的參數。

  要將 Item 名稱用於索引屬性,除非有明顯更好的名字(例如 System.String 的 Chars 屬性)。

  不要同時提供語義上等價的索引器和方法。

  不要在一個類型中提供具有不同名字的索引器。

  不要使用非默認的索引屬性。

  考慮在高層 API 的屬性值被修改時觸發屬性改變的通知事件。

  考慮在屬性值被外界修改時觸發通知事件。

  

5.3 構造函數的設計

  考慮提供簡單的構造函數,最好是默認構造函數。

  考慮用靜態工廠方法來代替構造函數 - 如果無法讓想要執行的操作的語義與新實例的構造函數直接對應,或者遵循構造函數的設計規範會讓人感覺不合理。

  要把構造函數的參數列表當做設置主要屬性的快捷方法。

  要用相同的名字來命名構造函數的參數和屬性 - 如果定義該構造函數參數的目的就是為了設置對應的屬性。

  要在構造函數中做最少的工作。

  要在適當的時候從實例構造函數中拋出異常。

  要在類中顯式地聲明公有的默認構造函數 - 如果這樣的構造函數是必需的。 

  避免在結構中顯式地定義默認構造函數。

  避免在對象的構造函數內部調用虛成員。

  要把靜態構造函數聲明為私有。

  不要從靜態構造函數中拋出異常。

  考慮以內聯的形式來初始化靜態字段,而不要顯式地定義靜態構造函數,這是因為運行庫能夠對那些沒有顯示定義靜態構造函數的類型進行性能優化。

5.4 事件的設計

  要在事件中使用術語“raise”,而不要使用“fire”或“trigger”。

  要用 System.EventHandler<T> 來定義事件處理函數,而不是手工創建新的委托來定義事件處理函數。

  考慮用 EventArgs 的子類來做事件的參數,除非百分之百確信該事件不需要給事件處理方法傳遞任何數據,在這種情況下可以直接使用 EeventArgs。

  要用受保護的虛方法來觸發事件。這只適用於非密封類中的非靜態事件,不適用於結構、密封類以及靜態事件。

  要讓觸發事件的受保護的方法帶一個參數,該參數的類型為事件參數類,該參數的名字應該為 e。

  不要在觸發非靜態事件時把 null 作為 sender 參數傳入。

  要在觸發靜態事件時把 null 作為 sender 參數傳入。

  不要在觸發事件時把 null 作為數據參數傳入。

  考慮觸發能夠被最終用戶取消的事件,這適用於前置事件。

  要把事件處理函數的返回類型定義為 void。

  要用 object 作為事件處理函數的第一個參數的類型,並將其命名為 sender。

  要用 System.EventArgs 或其子類作為事件處理函數的第二個參數的類型,並將其命名為 e。

  不要在事件處理函數中使用兩個以上的參數。

  

5.5 字段的設計

  不要提供公有的或受保護的實例字段。

  要用常量字段來表示永遠不會改變的常量。

  要用公有的靜態只讀字段來定義預定義的對象實例。

  不要把可變類型的實例賦值給只讀字段。

  

5.6 擴展方法

  避免草率地定義擴展方法,尤其是為別人的類型定義擴展方法。

  考慮在下面的場景中使用擴展方法。

  為一個接口的所有實現提供相關的輔助方法,而且這些功能可以通過核心接口來表達。

  如果增加一個實例方法會引入對其它類型的依賴關系,而依賴關系會破壞依賴關系的管理規則,那麽應該使用擴展方法。

  避免為 System.Object 定義擴展方法。

  不要把擴展方法和被擴展的類型放在同一個命名空間中 - 除非是為了把方法增加到接口中,或是為了對依賴關系進行管理。

  避免在定義兩個擴展方法時使用相同的簽名,即使它們位於不同的命名空間。

  考慮把擴展方法和被擴展的類型放在同一個命名空間 - 如果被擴展的類型是接口,而且該擴展方法的設計目的就是要用於大多數的情況甚至是所有的情況。

  不要把實現某個特性的擴展方法放在一個通常與其他特性相關聯的命名空間中。相反,該特性屬於哪個命名空間,就應該把對應的擴展方法放在那裏。

  避免使用太寬泛的名字(例如“Extensions”)來給擴展方法專用的命名空間命名,要使用更具描述性的名字(比如“Routing”)。

  

5.7 操作符重載

  避免定義操作符重載,除非該類型讓人感覺像個基本(內置)類型。

  考慮在讓人感覺應該想基本類型的類型中定義操作符重載。

  要為表示數值的結構(比如 System.Decimal)定義操作符重載。

  不要在定義操作符重載時耍小聰明。

  不要提供操作符重載,除非至少有一個操作數的類型是定義該操作符重載的類型。

  要以對稱的方式來重載操作符。

  考慮為每個重載過的操作符提供對應的方法,並用容易理解的名字來命名。

  不要提供類型轉換操作符 - 如果沒有明確的用戶需求。

  不要在定義類型轉換操作符時超越類型所在的領域。

  不要提供隱式類型轉換操作符 - 如果這樣的類型轉換可能會丟失精度。

  不要從隱式的強制類型轉換操作符中拋出異常。

  要拋出 System.InvalidCastException - 如果對強制類型轉換操作符的調用會丟失精度而該操作符承諾不丟失精度。

5.8 參數的設計

  要用類層次結構中最接近基類的類型作為參數的類型,同時要保證該類型能夠提供成員所需的功能。

  不要使用保留參數。

  不要把指針、指針數組及多維數組作為公有方法的參數。

  要把所有的輸出參數放在所有以值方式和以引用方式傳遞的參數的後面(不包括參數數組),即使這樣會在重載成員之間導致參數順序不一致也要如此。

  要在覆蓋成員或者實現接口成員時保持參數命名的一致。

  要用枚舉 - 如果不這樣做會導致參數中有兩個或兩個以上的布爾類型。

  不要使用布爾參數,除非百分之百肯定絕對不需要兩個以上的值。

  考慮在構造函數中,對確實只有兩種狀態的參數以及用來初始化布爾屬性的參數使用布爾類型。

  要對傳給共有的、受保護的或顯式實現的成員的參數進行驗證。如果驗證失敗,那麽應該拋出 System.ArgumentException 或其子類。

  要拋出 ArgumentNullExcepytion - 如果傳入的是 null 而該成員不支持 null。

  要驗證枚舉參數。

  不要用 Enum.IsDefined 來檢查枚舉的範圍。

  要清楚地知道傳入的可變參數可能會在驗證後發生改變。

  避免使用輸出參數或引用參數。

  不要以引用方式傳遞引用類型。

  考慮給數組參數增加 params 關鍵字 - 如果預計用戶會傳入為數不多的數組元素。

  避免使用 params 數組參數 - 如果絕大多數時候調用方要傳入的數組元素本來就已經在一個數組中了。

  不要使用 params 數組參數 - 如果要在成員中對數組進行修改。

  考慮在簡單的重載中使用 params 關鍵字,盡管更復雜的重載不能用 params 關鍵字。

  要對參數進行合理的排序,以便使用 params 關鍵字。

  考慮在對性能要求非常高的 API 中為參數數量較少的調用提供特殊的重載和相應的實現。

  要註意傳入的 params 數組參數可能是 null。

  不要使用 varargs 方法,又稱省略號。

  要為任何以指針為參數的成員提供一個替補成員,這是因為指針不符合 CLS 規範。

  避免對指針參數進行高開銷的檢查。

  要在設計用到指針的成員時遵循與指針相關的常用約定。

  

《.NET 設計規範》第 5 章:成員設計