25


4

getterでのオブジェクト作成は悪い習慣ですか?

このようなゲッターでオブジェクトを作成してみましょう:

public class Class1
{
       public string Id { get; set; }
       public string Oz { get; set; }
       public string Poznamka { get; set; }

       public Object object
       {
             get
             {
                  // maybe some more code
                  return new Object { Id = Id, poznamla = Poznamka, Oz = OZ };
             }
        }
 }

または、オブジェクトを作成して返すメソッドを作成する必要がありますか?

14 Answer


22


はい、それは悪い習慣です。

理想的には、ゲッターは何も変更したり作成したりするべきではありません(遅延読み込みを除いて、それでもコードがわかりにくくなると思います…​)。 そうすれば、意図しない副作用のリスクを最小限に抑えることができます。


16


プロパティはフィールドのように見えますが、メソッドです。 これは驚異的な量の混乱を引き起こすことが知られています。 プログラマーがフィールドにアクセスしているように見えるコードを見ると、プログラマーがプロパティに当てはまらない可能性がある多くの仮定があります。したがって、いくつかの一般的なプロパティ設計ガイドラインがあります。

  1. プロパティゲッターから異なる値を返すことは避けてください。 呼ばれたら 連続して複数回、プロパティメソッドは毎回異なる値を返す場合があります。フィールドは毎回同じ値を返します。

  2. プロパティメソッドは追加のメモリを必要とするか、参照を返す場合があります 実際にはオブジェクトの状態の一部ではないものに、返されるオブジェクトを変更しても元のオブジェクトには影響しません。フィールドを照会すると、常に元のオブジェクトの状態の一部であることが保証されているオブジェクトへの参照が返されます。 コピーを返すプロパティを操作することは開発者にとって非常に混乱を招く可能性があり、この特性はしばしば文書化されていません。

  3. プロパティをoutまたはrefパラメーターとして渡すことができないことを考慮してください メソッドへ;フィールドができます。

  4. 長時間実行されるプロパティゲッターは避けてください。 プロパティメソッドには時間がかかることがあります 実行する時間;フィールドアクセスは常にすぐに完了します。

  5. ゲッターから例外をスローしないでください。

  6. プロパティセッターが例外をスローした場合、以前の値を保持する

  7. 目に見える副作用を避けてください。

  8. これにより、プロパティが任意の順序で設定されることを許可します オブジェクトの一時的な無効な状態。

出典

「https://rads.stackoverflow.com/amzn/click/com/0735621632[C#経由のCLR]」、Jeffrey Richter。 第9章 プロパティをインテリジェントに定義する

「https://rads.stackoverflow.com/amzn/click/com/0321545613[Framework Design Guidelines]」第2版、Brad Abrams、Krzysztof Cwalina、第5.2章プロパティデザイン


8


ゲッターがアクセスされるたびに新しいオブジェクトを作成したい場合、それがその方法です。 このパターンは通常、http://en.wikipedia.org/wiki/Factory_method_pattern [Factory Method]と呼ばれます。

ただし、これは通常、プロパティでは必要ありません(つまり、 ゲッターとセッター)、そしてそれ自体は悪い習慣と見なされます。


4


はい、そうです …​ 外部からは、プロパティまたはフィールドにアクセスするかどうかにかかわらず、透明でなければなりません…​

フィールドまたはプロパティから2回読み取る場合、次の2つのことが予想されます。

  • オブジェクトの(外部)動作に影響はありません

  • 同じ結果が得られます

私はC#についての本当の知識は持っていませんが、次のことが私のポイントを明確にすることを願っています。 このように始めましょう:

Object o1 = myInst.object;
Object o2 = myInst.object;
o1.poznamka = "some note";

フィールドの場合、次のような条件が真になります。

o1 == o2;
o2.poznamka == "some note";

呼び出されるたびに新しいオブジェクトを返すゲッターでプロパティを使用すると、両方の条件がfalseになります…​

ゲッターはインスタンスの一時的なスナップショットを作成することを意図しているようです…​ それがあなたがしたいことなら、それを単純な方法にするよりも . あいまいさを回避します…​


2


プロパティは、すべての意図と目的に対して、フィールドのように機能する必要があります。 これは、例外がスローされず、新しいオブジェクトが作成されないことを意味します(したがって、プロパティがループで使用されている場合、多くの不要なオブジェクトを作成しないでください)

代わりにラッパークラスなどを使用してください。


2


私によると、何かが「プロパティ」である場合、ゲッターはオブジェクトに関連するプロパティ(基本的には既存のデータ)を返します。

あなたの場合、あなたはその時点でそのオブジェクトのプロパティではない何かを返しています。 オブジェクトのプロパティではなく、何らかのアクションの結果を返します。

代わりにGetMyObject()のようなメソッドを使用します。 特に「アクション」が発生する場合は、ほとんどの場合、プロパティ_name_よりもメソッドを持つことが最善だと思います。

そして、あなたのコードを見慣れていない他の開発者があなたのプロパティを見た後に何を期待するか想像してみてください。


1


プロパティは、計算フィールドを表す便利な方法です。

値自体がどのように到達したかに関係なく、オブジェクトについて何かを表す必要があります。 たとえば、対象のオブジェクトが請求書である場合、各品目のコストを合計して合計を返す必要があります。

オブジェクトのコピーを返すことはオブジェクトを説明するものではないため、質問に書かれていることはその規則を破ります。 オブジェクトの状態を明示的に変更せずに、プロパティの呼び出し間で戻り値が変更されると、オブジェクトモデルは破損します。

一般的に言えば、このような新しいオブジェクトを返すことは、ほぼ常にルールを破ります(今のところ反例を考えることはできません)。

また、プロパティを何度も簡単に無邪気に呼び出して同じコードを実行することができるプロパティの落とし穴もあります(遅くないことを願っています!)。


1


簡単にテストできるコードを作成するには、オブジェクトの初期化の分離を維持する必要があります。

つまり、テストケースでは、特定のアイテムをテストで保留することはできません。

Houseオブジェクトのように、kitchenオブジェクトに関連するものをテストしたくない。 庭だけをテストします。 そのため、いくつかのコンストラクターまたはゲッターでハウスクラスを開始し、オブジェクトを開始する間、テストをサポートする適切なコーディングはできません。


1


すでに行われたコメントとは別に、プロパティを介してフィールドを遅延ロードするときに、実際のデバッグの頭痛の種になります。

私はクラスを持っていました

private Collection moo;

public Collection Moo
{
  get
  {
    if (this.moo == null) this.moo = new Collection();
    return this.moo;
  }
}

それからクラスのどこかを参照するパブリックメソッドがありました

this.moo.Add(baa);

チェックせずにインスタンス化されました。

予想どおり、null参照例外がスローされました。 しかし、例外はUIスレッドにあったため、どこから来たのかすぐにはわかりません。 エラーを追跡し始め、追跡するたびにエラーが消えました。

しばらくの間、私は夢中になっていると思った。 デバッガー-エラーなし。 ランタイムエラー。 後で頭をひっかいて、エラーを見つけて、クラスのパブリックプロパティを表示するときに、* Visual Studioデバッガー*がコレクションをインスタンス化していることに気付きました。


0


多分、 `struct`には受け入れられるでしょう。 参照型の場合、いくつかの遅延ロードパターンを使用して一度だけ実行した場合にのみ、ゲッターで新しいオブジェクトを作成します。