設定のみのプロパティを持つことが推奨されないのはなぜですか?


9

今日、私の同僚が私のコードをレビューし、設定のみのプロパティを削除して、代わりにメソッドを使用することを提案しました。

私たち2人は他のことで忙しかったので、Property Design「フレームワークの設計ガイドライン」の本のセクションを見るように言われました。本の中で作家はただ避けようと言った:

ゲッターよりも広いアクセシビリティを持つセッターを持つプロパティ

そして今、私はなぜそれがセットオンリープロパティを持つことが推奨されないのか疑問に思っていますか?誰かが私のために明確にできますか?


6
セットオンリープロパティが適切だと思った状況を説明できますか?それは答えをもう少し適切にするかもしれません。
JohnFx

1
私は意味的に意味のある例を考えています。頭に浮かぶのはPasswordUserクラスのプロパティだけです。設定することはできますが、取得することはできません。その後、読み取り専用HashedPasswordプロパティを設定できます。セットを呼び出すと、ハッシュが実行され、HashedPasswordプロパティが変更されます。あなたがそうしたとしても、私はあなたに怒鳴りません。
スコットウィットロック、

回答:


15

期待と関係があるのではないでしょうか。セットのみのプロパティは一般的ではなく、プロパティは通常、あまり処理せずに値を格納するためだけに「ダム」セットに使用されます。セッターで多くの作業を行う場合は、メソッドを使用することをお勧めします。メソッドの実行には長い時間がかかる可能性があり、副作用がある可能性があると人々は期待しています。プロパティに同様の動作を実装すると、期待に反するコードが生成される可能性があります。

Microsoftのプロパティ使用ガイドラインの関連セクションは次のとおりです。

プロパティとメソッド

クラスライブラリの設計者は、多くの場合、クラスメンバーをプロパティまたはメソッドとして実装するかどうかを決定する必要があります。一般に、メソッドはアクションを表し、プロパティはデータを表します。次のガイドラインを使用して、これらのオプションから選択してください。

  • メンバーが論理データメンバーである場合は、プロパティを使用します。以下のメンバー宣言でNameは、はクラスの論理メンバーであるため、はプロパティです。
public string Name
{
    get 
    {
        return name;
    }
    set 
    {
        name = value;
    }
}

次の場合にメソッドを使用します。

  • 操作は、などの変換Object.ToStringです。
  • この操作は、ユーザーに結果をキャッシュすることを検討する必要があることを伝えたいほど高価です。
  • getアクセサーを使用してプロパティ値を取得すると、目に見える副作用があります。
  • メンバーを続けて2回呼び出すと、異なる結果になります。
  • 実行の順序は重要です。タイプのプロパティは、任意の順序で設定および取得できる必要があることに注意してください。
  • メンバーは静的ですが、変更可能な値を返します。
  • メンバーは配列を返します。配列を返すプロパティは、誤解を招く可能性があります。通常、ユーザーが内部状態を変更できないように、内部配列のコピーを返す必要があります。これは、ユーザーがそれをインデックス付きプロパティであると容易に想定できるという事実と相まって、非効率的なコードにつながります。次のコード例では、Methodsプロパティを呼び出すたびに、配列のコピーが作成されます。その結果、配列の2 ^ n + 1個のコピーが次のループで作成されます。
Type type = // Get a type.
for (int i = 0; i < type.Methods.Length; i++)
{
   if (type.Methods[i].Name.Equals ("text"))
   {
      // Perform some operation.
   }
}

[...長い例をスキップ...]

読み取り専用および書き込み専用プロパティ

ユーザーがプロパティの論理データメンバーを変更できない場合は、読み取り専用プロパティを使用する必要があります。書き込み専用プロパティを使用しないでください。


はい-最小の驚きの原則がここで機能します。
ポールブッチャー

6

それはほとんどの場合単に意味がないからです。設定できるが読み取れないプロパティはどれですか?

OOが現実の世界をよりよく表すことを意図している場合、設定のみのプロパティは、モデリングがかなりオフになっていることを示唆している可能性があります。

編集:参照:https : //stackoverflow.com/questions/4564928/are-set-only-properties-bad-practiceこれは本質的に直感的ではなく、設定のみのプロパティは基本的に別の名前のメソッドであるため、方法。


1
以前は設定のみのプロパティを使用しました。オブジェクトの動作を構成するために、オブジェクトのプライベートフィールドに書き込みます。これらは、外部コードが現在の値を知る必要はないが、変更する必要がある場合に役立ちます。もちろんそれはまれですが、私はそれが起こるのを見てきました。
メイソンウィーラー、

@メイソン-私は確かにあなたがそれらを使用してはならないということまでは決して行きませんが、それらは本質的にはルールではなく例外であるべきです。
ジョンホプキンス

@MasonWheelerはおおよそではないFoo Foo { private get; set; }ですか?私はそれを書き込みのみとは呼びません
Caleth

6

まあ、私はあなたが何かにプロパティを設定できるがそれを得ることができない場合、何かがあなたが設定した値を変更/上書きするかどうかは決してわからないと思います。設定した値に依存していて、(なんらかの理由で)取得したい時間までその値を保持できない場合、これは問題になる可能性があります。

設定のみのプロパティの代わりにメソッドを使用すると、ユーザーの混乱が少し少なくなります。名前方法のは、通常示しセット-またはGET-が、プロパティ名は、通常、その何かができることを示していないだけに設定することとない取得でき。プロパティが「ReadOnlyBackgroundColour」のようなものだったとしたら、他のプログラマーを混乱させることはないと思いますが、それは奇妙に見えます。


私は同意しますが、この場合、セッターメソッドはどのように異なりますか?
トラビスクリスチャン

1
@Travis Christian:OPはセッターはあるがゲッターはない状況で動作しているようです。したがって、彼らは何かを設定できますが、後で変更されるかどうかは決してわかりません。
FrustratedWithFormsDesigner

@Frustratedしかし、メソッドを使用して何かが再び変更されたかどうかもわかりません。
アダム・リア

@Anna Lear♦:ゲッターがある場合、コードに設定した値が突然疑わしい箇所がある場合は、少なくとも値を使用する前にテストできます。
FrustratedWithFormsDesigner

3
@フラストレーション同意する。問題は、設定専用のプロパティを使用することと、同じことをするためにメソッドを使用することについてでした。
アダムリア

-1

これは非常に古いトピックですが、この後半の段階で私の見解に飛び込んできたトピックであり、書き込み専用プロパティのケースを作成しようとするときにコメントをお願いします...

ActiveReportWebサイトの一部である一連のクラスがあり、インスタンス化され、ユーザーがいくつか選択した後にポストバックで実行されます。

VBコードは次のようになります。

  Public Class SomeReport
    Private greader As New GenericReporting.CommonReader("AStoredProcedure", 
                                      {New SqlParameter("budget_id", 0)})

    Public WriteOnly Property BudgetID As Integer
      Set(value As Integer)
        greader.Parameters("budget_id").Value = value
      End Set
    End Property

    Public Sub New(Optional budget_id As Integer = 0)
      ' This call is required by the designer.
      InitializeComponent()

      ' Add any initialization after the InitializeComponent() call.
      BudgetID = budget_id
    End Sub
  End Class

これらのレポートは、汎用のガットを使用しCommonReader、ストアドプロシージャとデフォルトSqlParameterの配列を受け取ります。各レポートには、レポート設計に応じて、インスタンス化のパラメーターとして渡すか、インスタンス化前にユーザーが設定できるWriteOnlyプロパティが関連付けられていますreports Runメソッドを呼び出す。

  '''''''''''''''''''''''
  ' Parameter taken from a user selected row of a GridView
  '
  Dim SomeBudgetID As Integer = gvBudgets.SelectedDataKey.Values(budget_id)

  '''''''''''''''''''''''      
  ' On Instantiation
  '
  Dim R as ActiveReport = New SomeReport(SomeBudgetID)
  R.Run()

  '''''''''''''''''''''''      
  ' Or On Instantiation using "With" syntax
  '
  Dim R as ActiveReport = New SomeReport() With {.BudgetID = SomeBudgetID}
  R.Run()

  '''''''''''''''''''''''
  ' Or After
  '
  Dim R as ActiveReport = New SomeReport()
  R.BudgetID = SomeBudgetID
  R.Run()

したがって、私が見るように、この場合は書き込み専用プロパティがあります

  1. SqlParametersは一種のジェネリックであるため、より強力な型チェックが可能
  2. レポート作成の柔軟性が向上し、すべてのパラメータが利用可能になった場合、レポートがすぐにインスタンス化されるか、利用可能になった後で追加されます。
  3. プロパティはインスタンス化時に「With」構文をサポートします
  4. パラメータはユーザーに認識され、レポートによって変更されないため、「getter」は本当に必要ですか?
  5. 以来SqlParameter、sはクラスではなく、プリミティブ値であり、書き込み専用のプロパティは、パラメータを設定するためのシンプルなインタフェースを可能に

それが私の考えです。

代わりにメソッドに変換できますか?確かに、インターフェースは...あまり良くないようです

  R2.BudgetID = SomeBudgetID

  R2.SetBudgetID(SomeBudgetID)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.