19

重複の可能性:
規則に関する質問: プロパティを使用するのではなく、いつ Getter/Setter 関数を使用しますか?

最近、ゲッターとセッターについて多くの異なる意見に出くわしたので、それを独自の質問にする必要があると考えました。

私の以前の質問は、セッターに副作用があってはならず、SetPropertyメソッドがより良い選択であると述べたコメント (後で削除されました) をすぐに受け取りました。

確かに、これはMicrosoft の意見でもあるようです。Resizedただし、フォームWidthHeightプロパティが設定されたときなど、それらのプロパティによってイベントが発生することがよくあります。OwenPはまた、「プロパティに例外をスローさせてはならない、プロパティに副作用があってはならない、順序は重要ではなく、プロパティは比較的迅速に返されるべきである」とも述べています。

しかし、Michael Stumは、setter 内でデータを検証する際に例外をスローする必要があると述べています。セッターが例外をスローしない場合、この質問に対する多くの回答が示唆するように、データを効果的に検証するにはどうすればよいでしょうか?

Microsoft のほぼすべての Control が行うように、イベントを発生させる必要がある場合はどうでしょうか? それなら、あなたのイベントに登録した人に翻弄されていませんか? ハンドラーが大量の情報を実行したり、エラーをスローしたりした場合、セッターはどうなりますか?

最後に、getter 内の遅延読み込みについてはどうでしょうか。これも以前のガイドラインに違反する可能性があります。

何を getter または setter に入れることが許容され、何をアクセサ メソッドのみに保持する必要がありますか?

編集:

MSDN の別の記事から:

およびメソッドは、通常、他のメソッドと同じですgetsetこれらは、任意のプログラム ロジックを実行し、例外をスローし、オーバーライドし、プログラミング言語で許可されている任意の修飾子で宣言することができます。ただし、プロパティは静的にすることもできることに注意してください。プロパティが静的である場合、メソッドgetsetメソッドで実行できることには制限があります。詳細については、プログラミング言語リファレンスを参照してください。

4

3 に答える 3

15

私の見解:

  1. セッターまたはゲッターが高価であることが予想される場合は、それをプロパティにせず、メソッドにします。

  2. プロパティの設定が変更によりイベントをトリガーする場合、これは問題ありません。他にどのようにリスナーに変更の通知を許可しますか? ただし、BeginInit/EndInit ペアを提供して、すべての変更が行われるまでイベントを抑制したい場合があります。通常、イベント ハンドラーはすぐに戻る必要がありますが、信頼できない場合は、別のスレッドでイベントを通知することをお勧めします。

  3. プロパティを設定すると、無効な値で例外がスローされる場合も問題ありません。これは、値が完全に間違っている場合に問題を知らせる合理的な方法です。また、一連のプロパティを設定してから、それらを使用して何かを行うメソッド (接続の確立など) を呼び出す場合もあります。これにより、プロパティが使用されるまで検証とエラー処理を延期できるため、プロパティは何もスローする必要がありません。

  4. プロパティへのアクセスは、予期せぬもので問題にならない限り、副作用を伴う場合があります。これは、getter での JIT インスタンス化が問題ないことを意味します。同様に、変更が行われるたびにインスタンスにダーティ フラグを設定することは問題ありません。これは、同じ値に対して異なる形式など、関連するプロパティを設定するためです。

  5. 値にアクセスするだけでなく何かを行う場合、それはメソッドである必要があります。メソッドは動詞であるため、接続の作成は Connection プロパティではなく OpenConnection() メソッドによって行われます。Connection プロパティは、使用中の接続を取得するか、インスタンスを別の接続にバインドするために使用されます。

編集 - 5 を追加、2 と 3 を変更

于 2010-05-25T20:55:57.383 に答える
1

ゲッター/設定に副作用があってはならないという考えには同意しますが、明らかでない副作用があってはならないと思います。

例外をスローする限り、(非常に基本的な意味で) プロパティを無効な値に設定している場合、検証例外は問題ありません。ただし、setter が一連の複雑なビジネス ルールの検証全体を実行している場合、または別のオブジェクトを更新しようとしている場合、または例外を引き起こす可能性のあるその他のことを行っている場合、それは良くありません。しかし、この問題は実際には例外自体の問題ではなく、セッターがオフになり、呼び出し元が予期しない (またはすべきでない) 多くの機能を密かに実行していることに起因します。

イベントも同様。セッターが「このプロパティが変更された」というイベントをスローしている場合、それは明らかな副作用であるため、問題ありません。しかし、それが他のカスタム イベントを発生させて、システムの別の部分でコードの隠れたチャンクを実行させる場合、それは悪いことです。

これは、getter で遅延読み込みを避けるのと同じ理由です。確かに、多くの場合、それらは物事を簡単にすることができますが、子オブジェクトをロードしたいときに正確に複雑なロジックが常に発生するため、物事をより混乱させることがあります。通常は、親オブジェクトを設定するときに子オブジェクトを明示的に読み込むコードを 1 行追加するだけで、オブジェクトの状態に関する多くの混乱を避けることができます。しかし、この側面は非常に主観的になる可能性があり、その多くは状況に依存します.

于 2010-05-25T20:57:34.783 に答える
0

とにかくC#で作業するときは、保守的なアプローチが最適であることが常にわかっています。プロパティは構文的にフィールドと同じであるため、フィールドのように機能する必要があります。例外、検証、おかしなことはありません。(実際、私のプロパティのほとんどは単純なフィールドとして開始され、絶対に必要になるまでプロパティにはなりません。) フィールド セットを取得または設定しているように見えるものを見つけた場合、それは取得または設定のようなものであるという考えです。機能 (例外がスローされない)、全体的な効率 (たとえば、変数を設定してもデリゲート呼び出しのカスケードがトリガーされない)、およびプログラムの状態への影響 (変数を設定するとその変数が設定され、ほとんど何でもできる多くのデリゲートを呼び出す必要はありません)。

プロパティ セットが行うべき賢明なことには、変更があったことを示すフラグの設定が含まれます。

set {
    if(this.value!=value) {
        this.changed=true;
        this.value=value;
    }
}

おそらく、実際には別のオブジェクトに値を設定します。たとえば、次のようになります。

set { this.otherObject.value=value; }

クラスの内部コードを単純化するために、入力を少し解きほぐします。

set {
    this.isValid=(value&Flags.IsValid)!=0;
    this.setting=value&Flags.SettingMask;
}

(もちろん、後者の 2 つのケースでは、get 関数は逆のことを行う可能性があります。)

特にデリゲートの呼び出し、検証の実行、例外のスローなど、より複雑なことが必要な場合は、関数の方が優れているというのが私の見解です。(かなり頻繁に、私のフィールドは get と set でプロパティに変わり、最終的には get プロパティと set 関数になります。) getter についても同様です。何かへの参照を返す場合は問題ありませんが、まったく新しい大きなオブジェクトを作成し、プロパティが読み取られるたびにそれを埋める場合は、それほどホットではありません。

于 2010-05-25T21:05:49.600 に答える