參數設計
注意
此內容是由 Pearson Education, Inc. 授權轉載自架構設計指導方針:可重複使用 .NET 程式庫的慣例、慣用語和模式,第 2 版。 該版於 2008 年出版,該書自那以後已於第三版進行了全面修訂。 此頁面上的某些資訊可能已過期。
本節提供參數設計的廣泛指導方針,包括具有檢查引數指導方針的區段。 此外,您應該參考具名引數中所述的指導方針。
✔️「務必」使用提供成員所需功能的最低衍生參數類型。
例如,假設您想要設計列舉集合的方法,並將每個項目列印到主控台。 例如,此類方法應該採用 IEnumerable 作為參數,而非 ArrayList 或 IList。
❌「請勿」使用保留參數。
如果未來版本需要更多成員的輸入,則可以新增新的多載。
❌「請勿」具有公開的方法,這些方法會採用指標、指標陣列或多維度陣列作為參數。
指標和多維度陣列相對難以正確使用。 幾乎所有情況下,都可以重新設計 API,以避免將這些類型視為參數。
✔️「務必」將所有 out
參數放在所有依值和 ref
參數之後 (排除參數陣列),即使其會導致多載之間的參數順序不一致 (請參閱成員多載)。
參數 out
可以視為額外的傳回值,並將其分組在一起,讓方法簽章更容易了解。
✔️「務必」在覆寫成員或實作介面成員時,在命名引數時保持一致。
這更能傳達方法之間的關聯性。
在列舉和布林值參數之間選擇
✔️「務必」在成員有兩個或多個布林值參數時使用列舉。
❌ 除非您確定絕對不需要超過兩個值,否則「請勿」使用布林值。
列舉提供您未來新增值的一些空間,但您應該留意將值新增至列舉的所有含意,如列舉設計中所述。
✔️請「考慮」將布林值用於真正兩個狀態值的建構函式參數,並且僅用來初始化布林值屬性。
驗證引數
✔️「務必」驗證傳遞至公用、受保護或明確實作成員的引數。 如果驗證失敗,則擲回 System.ArgumentException 或其中一個子類別。
請注意,實際驗證不一定必須在公用或受保護的成員本身發生。 在某些私人或內部常式中,可能會發生於較低層級。 主要的點在於公開給終端使用者的整個介面區會檢查引數。
✔️「務必」在傳遞 null 引數,且成員不支援 null 引數時擲回 ArgumentNullException。
✔️「務必」驗證列舉參數。
請勿假設列舉引數會位於列舉所定義的範圍內。 CLR 允許將任何整數值轉換成列舉值,即使列舉中未定義該值也一樣。
❌「請勿」將 Enum.IsDefined 用於列舉範圍檢查。
✔️「務必」注意,可變動的引數在驗證之後可能會變更。
如果成員具有安全性敏感性,建議您建立複本,然後驗證並處理引數。
參數傳遞
從架構設計工具的觀點來看,有三個主要的參數群組:依值參數、ref
參數和 out
參數。
當引數透過依值參數傳遞時,成員會收到傳入的實際引數複本。 如果引數是實值型別,則會將引數的複本放在堆疊上。 如果引數是參考型別,則會將參考的複本放在堆疊上。 最常見的 CLR 語言,例如 C#、VB.NET 和 C++,預設會依值傳遞參數。
當引數透過 ref
參數傳遞時,成員會收到所傳入實際引數的參考。 如果引數是實值型別,則會將引數的參考放在堆疊上。 如果引數是參考型別,則會將參考的參考放在堆疊上。 Ref
參數可用來允許成員修改呼叫端所傳遞的引數。
Out
參數類似於 ref
參數,但有一些小差異。 參數一開始會被視為未指派,且在指派一些值之前,無法在成員主體中讀取。 此外,參數必須在成員傳回之前指派一些值。
❌ 請「避免」使用 out
或 ref
參數。
使用 out
或 ref
參數需要使用指標的經驗、了解實值型別和參考型別之間的差異,並處理具有多個傳回值的方法。 此外,out
和 ref
參數之間的差異一般人不甚了解。 目標為一般使用者的 Framework 架構設計人員不應預期使用者會熟練地運用 out
或 ref
參數。
❌「請勿」以傳址方式傳遞參考型別。
規則有一些有限的例外狀況,例如可用來交換參考的方法。
參數數目可變的成員
可接受可變引數數目的成員會藉由提供陣列參數來表示。 例如,String 提供下列方法:
public class String {
public static string Format(string format, object[] parameters);
}
接著,使用者可以呼叫 String.Format 方法,如下所示:
String.Format("File {0} not found in {1}",new object[]{filename,directory});
將 C# params 關鍵字新增至陣列參數會將參數變更為所謂的 params 陣列參數,並提供建立暫存陣列的快捷方式。
public class String {
public static string Format(string format, params object[] parameters);
}
這樣做可讓使用者直接在引數清單中傳遞陣列項目,以呼叫方法。
String.Format("File {0} not found in {1}",filename,directory);
請注意,params 關鍵字只能新增至參數清單中的最後一個參數。
✔️ 如果您預期終端使用者傳遞具有少量項目的陣列,請「考慮」將 params 關鍵字新增至陣列參數。 如果預期會在常見案例中傳遞許多項目,使用者可能不會傳遞這些內嵌項目,因此不需要 params 關鍵字。
❌ 如果呼叫端幾乎一律在陣列中已經有輸入,請「避免」使用參數陣列。
例如,透過傳遞個別位元組,幾乎永遠不會呼叫具有位元組陣列參數的成員。 因此,.NET Framework 中的位元組陣列參數不會使用 params 關鍵字。
❌ 如果陣列是由採用 params 陣列參數的成員修改,「請勿」使用參數陣列。
由於許多編譯器會將引數轉換成呼叫位置的暫存陣列,陣列可能是暫存物件,因此對於陣列的任何修改都會遺失。
✔️ 請「考慮」在簡單多載中使用 params 關鍵字,即使更複雜的多載無法使用也一樣。
自問使用者是否將參數陣列的值放在單一多載中,即使其不在所有多載中也一樣。
✔️「務必」嘗試排序參數,使其可以使用 params 關鍵字。
✔️ 請「考慮」在極端重視效能的 API 中,為具有少量引數的呼叫提供特殊的多載和程式碼路徑。
這可讓您避免在以少量引數呼叫 API 時建立陣列物件。 採用陣列參數的單一形式並新增數值尾碼,以形成參數的名稱。
只有在您將進行整個程式碼路徑的特殊案例時,才應該這麼做,而不只是建立陣列並呼叫更一般的方法。
✔️「務必」注意,null 可以當做 params 陣列引數傳遞。
在處理之前,您應該先驗證陣列不是 null。
❌「請勿」使用 varargs
方法,或者稱為省略符號。
某些 CLR 語言,例如 C++,支援傳遞稱為 varargs
方法之變數參數清單的替代慣例。 慣例不應該用於架構中,因為其不符合 CLS 規範。
指標參數
一般而言,指標不應該出現在設計完善的 Managed 程式碼架構的公用介面區中。 大部分時候,應該封裝指標。 不過,在某些情況下,需要指標才能取得互通性,且在這種情況下使用指標是適當的。
✔️「務必」為採用指標引數的任何成員提供替代方案,因為指標不符合 CLS 規範。
❌「避免」對指標引數執行耗費最多資源的引數檢查。
✔️「務必」在使用指標設計成員時遵循常見的指標相關慣例。
例如,不需要傳遞起始索引,因為可以使用簡單的指標算術來完成相同的結果。
Portions © 2005, 2009 Microsoft Corporation. 著作權所有,並保留一切權利。
獲 Pearson Education, Inc. 的授權再版,從 Krzysztof Cwalina 和 Brad Abrams 撰寫,並在 2008 年 10 月 22 日由 Addison-Wesley Professional 出版,作為 Microsoft Windows Development Series 一部份的 Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition 節錄。