C#3.0自動プロパティ、フィールドに直接アクセスしてみませんか?
-
05-07-2019 - |
質問
そのようなクラスの属性内でget / setを使用するという新しいアプローチでは:
public string FirstName {
get; set;
}
単に、アクセサなしで属性FirstNameを単純に公開しないのはなぜですか?
解決
クラス(フィールド/属性)内の変数への直接アクセスに関する2つの大きな問題は次のとおりです。
1)フィールドに対して簡単にデータバインドすることはできません。
2)クラスからパブリックフィールドを公開する場合、後でそれらをプロパティに変更することはできません(たとえば、セッターに検証ロジックを追加するため)
他のヒント
将来、実装を変更しても、現在のインターフェースを使用したコードは壊れません。
たとえば、パブリックフィールドを持つ単純なクラスを実装し、いくつかの外部モジュールでクラスの使用を開始します。 1か月後、そのクラスに遅延読み込みを実装する必要があることがわかりました。次に、フィールドをプロパティに変換する必要があります。外部モジュールの観点から見ると、構文は同じように見えるかもしれませんが、そうではありません。プロパティは一連の関数であり、フィールドはクラスインスタンスのオフセットです。
プロパティを使用することにより、インターフェイスが変更されるリスクを効果的に削減できます。
これは主に、一般的なコーディング規約になったことに起因します。必要に応じて、カスタム処理コードを簡単に追加できます。しかし、あなたは正しいです、技術的にこれの本当の必要はありません。ただし、後でカスタム処理を追加する場合は、インターフェイスを壊さないようにするのに役立ちます。
このスタイルの表記法は、ゲッターとセッターのアクセシビリティを混在させる場合により便利です。たとえば、次のように記述できます。
public int Foo { get; private set; }
内部セッターを置くことも、ゲッターをプライベートにしてセッターをパブリックにすることもできます。
この表記法により、内部的に書き込み可能/外部から読み取り可能な値という古典的な問題を処理するためだけに、プライベート変数を明示的に記述する必要がなくなります。
重要なのは、コンパイラがプロパティを「内部」で関数ペアに変換し、プロパティを使用しているように見えるコードがある場合、ILにコンパイルされたときに実際に関数を呼び出すことです。
では、これをフィールドとして作成し、このフィールドを使用する別のアセンブリにコードがあるとします。後で実装が変更され、それをプロパティにして残りのコードから変更を隠すことにした場合でも、他のアセンブリを再コンパイルおよび再デプロイする必要があります。 get-goのプロパティである場合は、問題なく動作します。
質問者は次のことをしない理由を尋ねていると思います...
public string FirstName { }
上記に短縮できるのに、なぜアクセッサに悩まされるのですか。答えは、アクセサを要求することで、コードを読んでいる人がそれが標準のget / setであることを明らかにするからだと思います。それらがなければ、上記のように、これが自動的に実装されているのを見つけるのは困難です。
バグが発生し、どのメソッドがフィールドを変更しているのか、いつどのようにするのかを知る必要があるときは、もっと気になります。軽量のプロパティアクセサを前もって置くと、ラップしたフィールドに関連するバグが発生した場合の驚異的な量の痛みを軽減できます。私はそのような状況に数回来ましたが、特に再入可能性に関連していることが判明した場合、それは快適ではありません。
この作業を前もって行い、アクセッサにブレークポイントを付けるのは、他の方法よりはるかに簡単です。
99%のケースでは、公開フィールドを公開することは問題ありません。
一般的なアドバイスは、フィールドを使用することです:"クラスからパブリックフィールドを公開する場合、後でプロパティに変更することはできません"。私たちは皆、コードを将来に備えたいと思っていますが、この考え方にはいくつかの問題があります:
-
インターフェイスを変更すると、クラスのコンシューマーはおそらく再コンパイルできます。
-
データメンバーの99%が重要なプロパティになる必要はありません。 投機的一般性です。あなたは、決して役に立たないコードをたくさん書いています。
-
バージョン間でバイナリ互換性が必要な場合、プロパティにデータメンバーを作成するだけでは十分ではありません。少なくとも、インターフェースのみを公開し、すべてのコンストラクターを非表示にし、ファクトリーを公開する必要があります(以下のコードを参照)。
public class MyClass : IMyClass
{
public static IMyClass New(...)
{
return new MyClass(...);
}
}
これは困難な問題であり、不確実な将来に機能するコードを作成しようとしています。本当に難しい。
オブジェクトのカプセル化を保持し、コードを減らして読みやすくします。