プロパティのデザイン
Note
このコンテンツは、Pearson Education, Inc. の許可を得て、『Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition (フレームワーク設計ガイドライン: 再利用可能な .NET ライブラリの規約、表現形式、およびパターン、第 2 版)』から転載されています。 この版は 2008 年に出版され、その後、この本は第 3 版で全面的に改訂されました。 このページの情報の一部は古くなっている可能性があります。
プロパティは技術的にはメソッドとよく似ていますが、使用シナリオの観点からは非常に異なります。 それらは、スマートなフィールドと見なす必要があります。 フィールドの呼び出し構文と、メソッドの柔軟性を備えています。
✔️ 呼び出し元でプロパティの値を変更できないようにする必要がある場合は、取得専用プロパティを作成ます。
プロパティの型が変更可能な参照型である場合は、プロパティが取得専用であっても、プロパティの値を変更できることに注意してください。
❌ 設定専用のプロパティまたはセッターのあるプロパティに、ゲッターより広いアクセシビリティを提供しないでください。
たとえば、パブリック セッターとプロテクト ゲッターを持つプロパティは使用しないでください。
プロパティのゲッターを提供できない場合は、代わりにメソッドとして機能を実装します。 そのメソッドの名前は、Set
で始めて、その後にプロパティの名前を付けたものにすることを検討します。 たとえば、AppDomain には、CachePath
という名前の設定専用プロパティではなく、SetCachePath
という名前のメソッドを使用します。
✔️ すべてのプロパティに適切な既定値を提供し、既定値によってセキュリティ ホールや非常に非効率的なコードが発生しないようにします。
✔️ オブジェクトが一時的に無効な状態になることがあっても、プロパティを任意の順序で設定できるようにします。
同じオブジェクトの他のプロパティの値により、あるプロパティの一部の値が無効になる可能性があるポイントに、複数のプロパティが相互に関連付けられているのはよくあることです。 そのような場合は、相互に関連するプロパティがオブジェクトによって実際にまとめて使用されるまで、無効な状態による例外を延期する必要があります。
✔️ プロパティのセッターによって例外がスローされる場合は、前の値を保持します。
❌ プロパティのゲッターからは例外をスローしないでください。
プロパティのゲッターは、単純な操作にして、いかなる前提条件も持たないようにする必要があります。 ゲッターで例外がスローされる可能性がある場合は、メソッドとして再設計する必要があります。 このルールは、インデクサーには適用されないことに注意してください。そこでは、引数を検証した結果として、例外が発生することが予想されます。
インデックス付きプロパティの設計
インデックス付きプロパティは、パラメーターを持つことができる特殊なプロパティであり、配列のインデックス指定に似た特殊な構文を使用して呼び出すことができます。
インデックス付きプロパティは、通常、インデクサーと呼ばれます。 インデクサーは、論理コレクション内の項目へのアクセスを提供する API でのみ使用する必要があります。 たとえば、文字列は文字のコレクションであり、その文字にアクセスするために System.String にインデクサーが追加されています。
✔️ 内部配列に格納されているデータへのアクセスを提供するには、インデクサーの使用を検討します。
✔️ 項目のコレクションを表す型には、インデクサーを提供することを検討します。
❌ 複数のパラメーターでインデックス付きプロパティを使用することは避けてください。
設計で複数のパラメーターが必要な場合は、プロパティが論理コレクションへのアクセサーを実際に表しているかどうかを再検討します。 そうでない場合は、代わりにメソッドを使用します。 そのメソッドの名前は、Get
または Set
で始めることを検討します。
❌System.Int32、System.Int64、System.String、System.Object、または列挙型以外のパラメーターの型では、インデクサーを使用しないでください。
設計で他の型のパラメーターが必要な場合は、API が論理コレクションへのアクセサーを実際に表しているかどうかを厳しく再評価します。 そうでない場合は、メソッドを使用します。 そのメソッドの名前は、Get
または Set
で始めることを検討します。
✔️ 明らかにもっとよい名前がある場合を除き (たとえば、System.String
の Chars[] プロパティを参照)、インデックス付きプロパティには Item
という名前を使用します。
C# では、インデクサーは既定で Item という名前になります。 IndexerNameAttribute を使用して、この名前をカスタマイズできます。
❌ セマンティクス的に同等であるインデクサーとメソッドの両方を提供しないでください。
❌ 1 つの型でオーバーロードされたインデクサーのファミリを複数提供しないでください。
これは、C# コンパイラによって強制されます。
❌ 既定以外のインデックス付きプロパティは使用しないでください。
これは、C# コンパイラによって強制されます。
プロパティ変更通知イベント
場合によっては、プロパティ値の変更をユーザーに通知するイベントを提供すると便利です。 たとえば、Text
プロパティの値が変更された後で、System.Windows.Forms.Control
から TextChanged
イベントが発生します。
✔️ 高レベルの API (通常はデザイナー コンポーネント) のプロパティ値が変更されたら、変更通知イベントを発生させることを検討します。
オブジェクトのプロパティが変更されたことをユーザーが知るための適切なシナリオがある場合、オブジェクトでプロパティの変更通知イベントを発生させる必要があります。
ただし、基本データ型やコレクションなどの低レベルの API については、そのようなイベントを発生させるオーバーヘッドに価値があることはほとんどありません。 たとえば、新しい項目がリストに追加されて、Count
プロパティが変更されたときでも、List<T> からはそのようなイベントは発生しません。
✔️ プロパティの値が外部からの強制によって変更された場合は、変更通知イベントを発生させることを検討します。
プロパティ値が何らかの外部強制 (オブジェクトのメソッドを呼び出す以外の方法) によって変更された場合、イベントの発生は、値が変更されていること、および変更されたことを開発者に示します。 テキスト ボックス コントロールの Text
プロパティがよい例です。 ユーザーが TextBox
にテキストを入力すると、プロパティ値が自動的に変更されます。
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. の許可を得て再印刷されています。