C#のプロパティには、状態の変化を通知することに加えて副作用がありますか?
いくつかの異なる方法で使用されるプロパティを見てきました。初めてアクセスされたときに値を読み込むプロパティから、別のページへのリダイレクトを引き起こすなどの大きな副作用を持つプロパティにアクセスします。
C#のプロパティには、状態の変化を通知することに加えて副作用がありますか?
いくつかの異なる方法で使用されるプロパティを見てきました。初めてアクセスされたときに値を読み込むプロパティから、別のページへのリダイレクトを引き起こすなどの大きな副作用を持つプロパティにアクセスします。
回答:
プロパティセッターはほとんどすべての場合に副作用があるため、読み取り専用プロパティ、または少なくともプロパティgetterについて話していると思います。それ以外の場合はあまり役に立ちません。
一般的に、優れた設計は、最小限の驚きの原則に従います。発信者があなたに期待していないことは、特に将来の結果が変わる可能性がある場合はしないでください。
一般的に、これはプロパティゲッターに副作用がないことを意味します。
ただし、「副作用」とはどういう意味か注意しましょう。
副作用は、技術的には、ある任意の状態の変更。それは公的にアクセス可能な状態かもしれないし、あるいは...完全にプライベートな状態かもしれない。
遅延/遅延ローダーは、ほぼ排他的な状態の一例です。そのリソースを解放するのが呼び出し側の責任でない限り、実際には、遅延初期化を使用することにより、実際に驚きと複雑さを軽減しています。呼び出し元は、通常、内部構造の初期化を明示的に通知する必要はありません。したがって、遅延初期化は上記の原則に違反しません。
別の例は、同期されたプロパティです。メソッドをスレッドセーフにするには、多くの場合、クリティカルセクションまたはミューテックスによって保護する必要があります。クリティカルセクションに入るか、ミューテックスを取得することは副作用です。状態、通常はグローバル状態を変更しています。ただし、この副作用は、さらに悪い種類の驚き-別のスレッドによってデータが変更される(または、さらに悪いことに、部分的に変更される)驚きを防ぐために必要です。
そのため、次の制限を少し緩めます。プロパティの読み取りには、目に見える副作用や、セマンティクスを変更する副作用があってはなりません。
発信者が副作用の影響を受ける可能性がなく、副作用に気付かない場合でも、その副作用は害を及ぼしません。特定の副作用の存在を確認するテストを作成することが不可能な場合、プライベート実装の詳細としてラベル付けするのに十分にローカライズされているため、外界に対する正当な懸念はありません。
しかし、注意してください。経験則として、あなたがすべきことが多いプライベート実装の詳細であることを考えるかもしれないもの、予想外に漏れると、公開になる可能性があるため、副作用を避けるようにしてください。
あなたの質問に答えます:フォームのWidthプロパティを変更するとどうなりますか?
私の頭の上から、これは:
(免責事項:私はDelphi開発者であり、.NET開発者ではありません。これはC#で100%正確ではないかもしれませんが、元の.NETフレームワークのどれだけがDelphiに基づいているかを考えると、かなり近いと思います。)
これらの「副作用」はすべて、フォームのWidthプロパティを変更すると発生します。それらのいずれかが何らかの形で不適切または誤っているように見えますか?
見てみましょうマイクロソフトのデザインルール、それらの特に1を:
...これらの条件のいずれかが存在する場合、メソッドはプロパティになるのに適した候補です。
- 引数を取らず、オブジェクトの状態情報を返します。
- 単一の引数を受け入れて、オブジェクトの状態の一部を設定します。
プロパティはフィールドのように振る舞う必要があります。メソッドができない場合は、プロパティに変更しないでください。以下の状況では、メソッドはプロパティよりも優れています。
- このメソッドは、時間がかかる操作を実行します。このメソッドは、フィールドの値を設定または取得するのに必要な時間よりも明らかに遅いです。
- メソッドは変換を実行します。フィールドにアクセスしても、保存されているデータの変換されたバージョンは返されません。
- Getメソッドには、目に見える副作用があります。フィールドの値を取得しても、副作用は発生しません。
- 実行の順序は重要です。フィールドの値の設定は、他の操作の発生に依存しません。
- メソッドを連続して2回呼び出すと、異なる結果が作成されます。
- このメソッドは静的ですが、呼び出し元が変更できるオブジェクトを返します。フィールドの値を取得しても、呼び出し側はフィールドに保存されているデータを変更できません。
- メソッドは配列を返します...
プログラミングには絶対的なものはほとんどありません。あなたの質問に答えるには、オブジェクトのいくつかの望ましいプロパティを調べ、それが私たちのケースに当てはまるかどうかを確認する必要があります
これらの質問のいくつかに「はい」と答えた場合、プロパティとその副作用について非常に慎重に検討することをお勧めします。値を更新すること自体が副作用であるため、副作用と言うときは二次的な副作用を意味すると思います。
一般的に副作用が多いほど、クラスのテストは難しくなります。二次的な副作用が多ければ多いほど、並行処理の処理は難しくなりますが、それはとにかくいくつかの主要な設計思想を必要とする難しい問題です。
大きな落とし穴は、おそらくあなたのクラスを「ブラックボックス」として扱う人向けです。プロパティを読んだからといって何らかの状態が変化したり、別の変更によって他のプロパティが変化したりする可能性があります。カスケード更新まで)。
そのため、一般的にいって、プロパティはできるだけ簡単に推論できるようにし、できるだけシンプルにする必要があります。それは、設計の決定に含まれていることを意味します。優れたプログラマーは常にルールを破ることができますが、本当に本当に正当な理由があることを確認してください:)