共用方式為


參數設計

注意

此內容是由 Pearson Education, Inc. 授權轉載自架構設計指導方針:可重複使用 .NET 程式庫的慣例、慣用語和模式,第 2 版。 該版於 2008 年出版,該書自那以後已於第三版進行了全面修訂。 此頁面上的某些資訊可能已過期。

本節提供參數設計的廣泛指導方針,包括具有檢查引數指導方針的區段。 此外,您應該參考具名引數中所述的指導方針。

✔️「務必」使用提供成員所需功能的最低衍生參數類型。

例如,假設您想要設計列舉集合的方法,並將每個項目列印到主控台。 例如,此類方法應該採用 IEnumerable 作為參數,而非 ArrayListIList

❌「請勿」使用保留參數。

如果未來版本需要更多成員的輸入,則可以新增新的多載。

❌「請勿」具有公開的方法,這些方法會採用指標、指標陣列或多維度陣列作為參數。

指標和多維度陣列相對難以正確使用。 幾乎所有情況下,都可以重新設計 API,以避免將這些類型視為參數。

✔️「務必」將所有 out 參數放在所有依值和 ref 參數之後 (排除參數陣列),即使其會導致多載之間的參數順序不一致 (請參閱成員多載)。

參數 out 可以視為額外的傳回值,並將其分組在一起,讓方法簽章更容易了解。

✔️「務必」在覆寫成員或實作介面成員時,在命名引數時保持一致。

這更能傳達方法之間的關聯性。

在列舉和布林值參數之間選擇

✔️「務必」在成員有兩個或多個布林值參數時使用列舉。

❌ 除非您確定絕對不需要超過兩個值,否則「請勿」使用布林值。

列舉提供您未來新增值的一些空間,但您應該留意將值新增至列舉的所有含意,如列舉設計中所述。

✔️請「考慮」將布林值用於真正兩個狀態值的建構函式參數,並且僅用來初始化布林值屬性。

驗證引數

✔️「務必」驗證傳遞至公用、受保護或明確實作成員的引數。 如果驗證失敗,則擲回 System.ArgumentException 或其中一個子類別。

請注意,實際驗證不一定必須在公用或受保護的成員本身發生。 在某些私人或內部常式中,可能會發生於較低層級。 主要的點在於公開給終端使用者的整個介面區會檢查引數。

✔️「務必」在傳遞 null 引數,且成員不支援 null 引數時擲回 ArgumentNullException

✔️「務必」驗證列舉參數。

請勿假設列舉引數會位於列舉所定義的範圍內。 CLR 允許將任何整數值轉換成列舉值,即使列舉中未定義該值也一樣。

❌「請勿」將 Enum.IsDefined 用於列舉範圍檢查。

✔️「務必」注意,可變動的引數在驗證之後可能會變更。

如果成員具有安全性敏感性,建議您建立複本,然後驗證並處理引數。

參數傳遞

從架構設計工具的觀點來看,有三個主要的參數群組:依值參數、ref 參數和 out 參數。

當引數透過依值參數傳遞時,成員會收到傳入的實際引數複本。 如果引數是實值型別,則會將引數的複本放在堆疊上。 如果引數是參考型別,則會將參考的複本放在堆疊上。 最常見的 CLR 語言,例如 C#、VB.NET 和 C++,預設會依值傳遞參數。

當引數透過 ref 參數傳遞時,成員會收到所傳入實際引數的參考。 如果引數是實值型別,則會將引數的參考放在堆疊上。 如果引數是參考型別,則會將參考的參考放在堆疊上。 Ref 參數可用來允許成員修改呼叫端所傳遞的引數。

Out 參數類似於 ref 參數,但有一些小差異。 參數一開始會被視為未指派,且在指派一些值之前,無法在成員主體中讀取。 此外,參數必須在成員傳回之前指派一些值。

❌ 請「避免」使用 outref 參數。

使用 outref 參數需要使用指標的經驗、了解實值型別和參考型別之間的差異,並處理具有多個傳回值的方法。 此外,outref 參數之間的差異一般人不甚了解。 目標為一般使用者的 Framework 架構設計人員不應預期使用者會熟練地運用 outref 參數。

❌「請勿」以傳址方式傳遞參考型別。

規則有一些有限的例外狀況,例如可用來交換參考的方法。

參數數目可變的成員

可接受可變引數數目的成員會藉由提供陣列參數來表示。 例如,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 節錄。

另請參閱