パラメーターのデザイン
Note
このコンテンツは、Pearson Education, Inc. の許可を得て、『Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition (フレームワーク設計ガイドライン: 再利用可能な .NET ライブラリの規約、表現形式、およびパターン、第 2 版)』から転載されています。 この版は 2008 年に出版され、その後、この本は第 3 版で全面的に改訂されました。 このページの情報の一部は古くなっている可能性があります。
このセクションでは、引数のチェックに関するガイドラインなど、パラメーターの設計に関する広範なガイドラインを示します。 また、「パラメーターに名前を付ける」で説明されているガイドラインも参照してください。
✔️ メンバーで必要とされる機能を提供する最小限の派生のパラメーター型を使用します。
たとえば、コレクションを列挙して、各項目をコンソールに出力するメソッドを設計するとします。 このようなメソッドは、たとえば ArrayList や IList ではなく、IEnumerable をパラメーターとして受け取る必要があります。
❌ 予約済みのパラメーターは使用しないでください。
将来のバージョンでメンバーへの入力を増やす必要がある場合は、新しいオーバーロードを追加できます。
❌ パラメーターとしてポインター、ポインターの配列、または多次元配列を受け取る、パブリックに公開されたメソッドを使用しないでください。
ポインターと多次元配列は、適切に使用するのが比較的困難です。 ほとんどの場合、これらの型をパラメーターとして受け取らないように、API を再設計することができます。
✔️ オーバーロードの間でパラメーターの順序に不一致が発生するようになっても (「メンバーのオーバーロード」を参照)、すべての out
パラメーターを、値渡しおよび ref
パラメーターの後に配置します (パラメーター配列を除きます)。
out
パラメーターは、追加の戻り値と考えることができ、これらをまとめてグループ化することで、メソッドのシグネチャがわかりやすくなります。
✔️ メンバーをオーバーライドするときや、インターフェイス メンバーを実装するときは、パラメーターに一貫した名前を付けます。
これにより、メソッド間の関係をより適切に伝えられます。
列挙型パラメーターとブール型パラメーターの選択
✔️ そうしないとメンバーに複数のブール型パラメーターが含まれるようになる場合は、列挙型を使用ます。
❌ 3 つ以上の値が必要にならないことが絶対に確実である場合を除き、ブール型は使用しないでください。
列挙型を使用すると、後で値を追加できるようになりますが、列挙型に値を追加することによるすべての影響を把握しておく必要があります。これについては「列挙型のデザイン」を参照してください。
✔️ コンストラクターのパラメーターが間違いなく 2 つの状態の値であり、ブール型プロパティの初期化だけに使用される場合は、ブール型を使用することを検討します。
引数の検証
✔️ パブリック、プロテクト、または明示的に実装されるメンバーに渡される引数については、検証を行います。 検証が失敗した場合は、System.ArgumentException またはそのサブクラスのいずれかをスローします。
パブリックまたはプロテクトのメンバー自体では、実際の検証を必ずしも行う必要がないことに注意してください。 これは、一部のプライベートまたは内部のルーチンの下位レベルで発生する可能性があります。 主要なポイントは、エンド ユーザーに公開されている領域全体で、引数をチェックすることです。
✔️ null 引数が渡され、メンバーが null 引数をサポートしていない場合は、ArgumentNullException をスローします。
✔️ 列挙型パラメーターの検証を行います。
列挙型引数はその列挙型によって定義されている範囲内であると仮定しないでください。 CLR では、値が列挙型で定義されていない場合であっても、任意の整数値を列挙値にキャストできます。
❌ 列挙範囲のチェックには Enum.IsDefined を使用しないでください。
✔️ 変更可能な引数は検証後に変更される可能性があることに注意してください。
メンバーのセキュリティが重要な場合は、コピーを作成してから、引数を検証して処理することをお勧めします。
パラメーターの引き渡し
フレームワーク デザイナーの観点から見ると、パラメーターの主なグループには、値渡しパラメーター、ref
パラメーター、out
パラメーターの 3 つがあります。
値渡しパラメーターによって引数が渡されると、メンバーは渡された実際の引数のコピーを受け取ります。 引数が値型の場合は、引数のコピーがスタックに格納されます。 引数が参照型の場合は、参照のコピーがスタックに格納されます。 C#、VB.NET、C++ などのほとんどの一般的な CLR 言語では、値渡しのパラメーターが既定です。
引数が ref
パラメーターによって渡されると、メンバーは渡された実際の引数への参照を受け取ります。 引数が値型の場合は、引数への参照がスタックに格納されます。 引数が参照型の場合は、参照への参照がスタックに格納されます。 Ref
パラメーターを使用すると、呼び出し元によって渡された引数を、メンバーが変更できるようにすることができます。
Out
パラメーターは ref
パラメーターに似ていますが、いくつか小さな違いがあります。 パラメーターは、最初は未割り当てと見なされ、何らかの値が割り当てられるまで、メンバー本体で読み取ることはできません。 また、メンバーから戻る前に、パラメーターに何らかの値を割り当てる必要があります。
❌out
または ref
パラメーターは使用しないようにしてください。
out
または ref
パラメーターを使用するには、ポインターの使用経験、値型と参照型の違いの理解、および複数の戻り値を持つメソッドの処理が必要になります。 また、out
パラメーターと ref
パラメーターの違いはあまり理解されていません。 開発者全般に向けてフレームワークをデザインする場合、ユーザーが 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 キーワードは必要ありません。
❌ 通常、呼び出し元で配列に既に入力が格納されている場合は、params 配列を使用しないでください。
たとえば、バイト配列のパラメーターを持つメンバーは、個々のバイトを渡すことで呼び出されることはほとんどありません。 このため、.NET Framework のバイト配列パラメーターでは、params キーワードは使用されません。
❌ params 配列パラメーターを受け取るメンバーによって配列が変更される場合は、params 配列を使用しないでください。
多くのコンパイラでは、メンバーへの引数が呼び出しサイトで一時配列に変換され、その配列は一時オブジェクトである可能性があるため、配列に対する変更はすべて失われます。
✔️ より複雑なオーバーロードでは使用できない場合でも、単純なオーバーロードでは params キーワードの使用を検討します。
すべてのオーバーロードではなくたとえ 1 つのオーバーロードであっても、params 配列を使用するとユーザーにとって価値があるかどうかを考えてください。
✔️ params キーワードを使用できるように、パラメーターを並べ替えてみます。
✔️ 非常にパフォーマンスが重要な API では、少数の引数を使用する呼び出しに対して、特別なオーバーロードとコード パスを提供することを検討します。
このようにすると、API が少数の引数で呼び出される場合、配列オブジェクトを作成しなくて済むようになります。 配列パラメーターの単数形を使用し、数値のサフィックスを追加することによって、パラメーターの名前を作成します。
これは、単に配列を作成してより一般的なメソッドを呼び出すだけでなく、コードパス全体を特殊なケースにする場合にのみ実行してください。
✔️ params 配列引数として null が渡される場合があることに注意してください。
処理する前に、配列が null でないことを検証する必要があります。
❌varargs
メソッドを使用しないでください。そうしないと、省略として認識されます。
C++ などの一部の CLR 言語では、varargs
メソッドと呼ばれる変数パラメーター リストを渡すための代替規則がサポートされています。 この規則は、CLS に準拠していないため、フレームワークでは使用しないでください。
ポインター パラメーター
一般に、適切に設計されたマネージド コード フレームワークの公開領域で、ポインターを使用することはできません。 ほとんどの場合、ポインターはカプセル化する必要があります。 ただし、相互運用性の理由からポインターが必要になることがあり、そのような場合にポインターを使用するのは適切です。
✔️ ポインターは CLS に準拠していないため、ポインター引数を受け取るメンバーには代替手段を提供します。
❌ ポインター引数の負荷の高い引数チェックは行わないでください。
✔️ ポインターを使用するメンバーを設計するときは、ポインター関連の一般的な規則に従います。
たとえば、簡単なポインター演算を使用して同じ結果を得ることができるため、開始インデックスを渡す必要はありません。
Portions © 2005, 2009 Microsoft Corporation. All rights reserved.
2008 年 10 月 22 日に Microsoft Windows Development シリーズの一部として、Addison-Wesley Professional によって発行された、Krzysztof Cwalina および Brad Abrams による「Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition」 (フレームワーク デザイン ガイドライン: 再利用可能な .NET ライブラリの規則、用法、パターン、第 2 版) から Pearson Education, Inc. の許可を得て再印刷されています。