web-dev-qa-db-ja.com

プロパティへの偶発的な変更を防ぐためのSetPropertyメソッドの使用

以下を行うことは良い/悪い習慣ですか?

public class MyClass {
  public MyType MyProperty { get; private set; }

  public void SetMyProperty(MyType myProperty) {
    MyProperty = myProperty;
  }
}

私の意図は、クラスの外でMyPropertyが誤って変更されないようにすることです。ただし、必要に応じて変更できます。

また、MyTypeが参照型の場合、private set防止、例えば:

instanceOfMyClass.MyProperty.SomeField = 2;

つまり、MyPropertyとそのすべてのメンバーを読み取り専用にしますか、それともMyPropertyへの参照だけにしますか?

これがインテリジェントな質問ではないようでしたら申し訳ありません。私は初心者だと思います。

6
James

私の意図は、クラス外でMyPropertyが誤って変更されないようにすることです。ただし、必要に応じて変更できます。

正直なところ、これを行う意味はわかりません。呼び出す

myClass.MyProperty = new MyType();

呼び出すよりも意図的ではありません

myClass.SetMyProperty(new MyType());

読みやすさの点では、個別のメソッドではなく、より直感的なセッターアプローチのほうがはるかに良いと思います。そして、誰かがMyPropertyの値を変更できるようにしたくない場合は、セッターまたはメソッドを介して許可しないでください。

つまり、MyPropertyとそのすべてのフィールドを読み取り専用にしますか、それともMyPropertyへの参照だけにしますか?

MyPropertyへの参照のみ。 MyTypeは、人々がそのプロパティを変更できないようにする場合、 不変タイプ である必要があります。

10
Adam Lear

プライベートセッターを持つことは完全に有効な慣行であり、私はこれを自分で行うことがよくあります。これは、OOPの基礎の1つであるカプセル化の一部です。

ただし、設定にパブリックメソッドを提供しても意味がありません。値を設定できるようにするには、パブリックセッターを使用します。

あなたが尋ねたように、プライベートセッターを使用しても、基になるフィールドの値をクラスの外で変更することはできません(コンパイラーが生成します-基になるフィールドはまだあります)。これは、この値を変更するパブリック関数を提供しない限りです。

4
Oded

「SetProperty」メソッドを終日使用したい場合は、Javaでプログラミングします。

さらに、パブリックgetプロパティがある場合、そのプロパティにプライベートセットがある場合でも、プロパティの値のメンバーを変更できます。多くの配列クラスなど、一部のクラスはこの問題を解決するために「読み取り専用」ラッパーを提供します。 http://msdn.Microsoft.com/en-us/library/53kysx7b.aspx

2
whatsisname

ゲッターを提供しても、クラスのプロパティを変更できます。あなたがそれを避けたいなら、私はインスタンスをクローンします

private MyType _myProperty;
public MyType MyProperty { get { return new MyType(_myProperty); } set { _myProperty = value; } }
1
Dante

何かが読み取り/書き込みプロパティとして動作する場合、通常は読み取り/書き込みプロパティを使用して実装する必要があります。一方、プロパティの値を変更できるという事実は、読み取り/書き込みプロパティのように動作することを意味しません。一般に、何かが「クリーン」プロパティとして機能する場合は、読み取り/書き込みプロパティとしてのみ実装する必要があることをお勧めします(以下で説明)。ただし、.Netの多くのクラスは、私が提案するものに適合しない。多くの場合、これは完全な哲学的背景が完全に解明される前にフレームワークを実装するようにという時間的なプレッシャーに起因すると推測します。

以下の場合、読み書きプロパティはクリーンであると見なします。

  1. それを読み取ることは副次的な影響を与えることはなく、メソッド呼び出しまたはそのプロパティへの書き込みがない場合は常に同じ値が生成されます。
  2. それを読み取ってから、読み取った値を書き戻しても効果はありません。
  3. メソッド呼び出しを介さずに書き込みに続く読み取りは、常に書き込まれた値になります。
  4. メソッドを呼び出さずにプロパティを複数回書き込むと、最後の書き込みのみを実行するのと同じ効果があります。
  5. 間にメソッド呼び出しがない場合、クリーンプロパティをXに設定してから他のプロパティをYに設定した場合の効果は、他のプロパティをYに設定してからクリーンプロパティをXに設定した場合と同じになります。

「クリーン」プロパティへの書き込みが他の読み取り専用プロパティの状態に影響を与えることは完全に許容されることに注意してください。複数のプロパティを設定した場合の影響は、書き込まれた値に依存しますが、書き込みが発生する順序には依存しません。 myRectが(X = 1、Y = 2、Width = 3、Height = 4)に初期化されている場合、MyRect.X=2; MyRect.Top = MyRect.Right;の効果は、MyRect.X = 2; MyRect.Top = 5;またはMyRect.Top = 5; MyRect.X = 2;と同じでなくても、同じでなければなりません。 MyRect.Top = MyRect.Right; MyRect.X = 2;として。

多くの.netクラスは、これらの定義による「不明瞭」な方法でプロパティを使用します。たとえば、これらの定義を使用すると、StringBuilder .Lengthはおそらく読み取り専用プロパティになりますが、Textはおそらく読み取り/書き込みプロパティになる可能性があります(Textの読み取りは同等です) ToString()に書き込みますが、書き込み中はそれをクリアしてAppend)を実行するのと同じです。

オブジェクトのプロパティを変更できるさまざまな状況がありますが、それらは「クリーンな読み取り/書き込みプロパティ」と見なすべきではありません。その中で:

  1. (X、Y、Width、Height)を格納し、読み取り/書き込みプロパティとして公開する四角形は、 `Right`プロパティを持っている可能性がありますが、設定しようとすると他の1つに影響します。
  2. オブジェクトは、 `IDisposable`オブジェクトへの参照を保持し、不要になったときにそのオブジェクトに対して` Dispose`を呼び出す可能性があります。メソッド `SetXXAndTakeOwnership()`はより明確なセマンティクスを提供します(プロパティを設定する前に古いオブジェクトを `Dispose`と呼びます)は読み取り/書き込みプロパティよりも明確なセマンティクスを提供します。
  3. 一部のオブジェクトには、特定の値の組み合わせにのみ設定できるプロパティがある場合があります。このようなすべてのプロパティを一度に設定するメソッドがあると、プロパティを個別に設定してシーケンス処理を心配するよりもはるかに優れている場合があります。プロパティは古い値と新しい値に依存する順序で記述する必要があるため、 `ProgressBar`はこの点で特に厄介です。 `ProgressBar`が現在7/9が完了したことを示している場合、3/5に変更するには、` Maximum`の前に `Value`を書き込む必要がありますが、14/19に設定するには、最初に` Maximum`を更新する必要があります。値と最大値の両方のパラメーターを受け入れ、両方を同時に更新する `SetFraction`メソッドは、はるかに優れていたでしょう。
  4. タイマーの残り時間などの一部のプロパティは、書き込まれた時間と読み取られた時間の間で変化する場合があります。そのようなことは、読み取り専用のプロパティとして完全にうまくいくかもしれません(それらを読み取るには時間がかかり、時間がかかる行為は将来の読み取りに影響を与える可能性がありますが、そのような副作用はシステムが実行する他のコードと何ら変わりません)が違反しますクリーンプロパティが最後に読み取った値を返すというルール。

これらの条件のいずれか(または他の多くのリスト-リストがほとんど網羅されていない場合)が適用される場合は、読み取り/書き込みプロパティではなくSetXXメソッドを使用します。

0
supercat