パブリックフィールドと自動プロパティ


353

フィールドを外部に公開するのではなく、クラスフィールドのゲッターメソッドとセッターメソッド(C#のプロパティ)を作成してカプセル化を保護する必要があるとよく言われます。

しかし、フィールドが値を保持するためだけに存在し、取得または設定するための計算を必要としない場合がよくあります。これらについては、私たちはすべてこの数を行います:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

まあ、私は自白があります。私はそれをすべて書くことに耐えられなかったので(本当に、それを書く必要はなく、それを見る必要がありました)、私は不正に行き、パブリックフィールドを使用しました。

その後、C#3.0が追加され、自動プロパティが追加されたことがわかります。

public class Book
{
    public string Title {get; set;} 
}

どちらかと言うと整然としていますが、私は感謝していますが、実際には、パブリックフィールドを作成することと何が違うのでしょうか。

public class Book
{
    public string Title;
}


6
セッターにブレークポイントを設定できるように、フィールドをプロパティに変換しました
Ian Ringrose

1
私はフィールドをプロパティにリファクタリングしなければならないという道を進んでいくと、不必要な頭痛の種につながるため、私物ではないものを作る傾向があります。 プロパティ、フィールド、メソッド。オーマイ!過去に私を悩ませてきた非互換性を呼び出します。
Steven Wexler、2014年

2
propコードスニペットは、それが高速でプロパティを作成することができます。propタブを入力するだけです。
遠ナム

回答:


175

少し前にあった関連する質問で、いくつかの違いを説明するジェフのブログへの投稿へのリンクがありました。

プロパティとパブリック変数

  • リフレクションは変数とプロパティでは動作が異なるため、リフレクションに依存している場合は、すべてのプロパティを使用する方が簡単です。
  • 変数に対してデータバインドすることはできません。
  • 変数をプロパティに変更すると、重大な変更になります。例えば:

    TryGetTitle(out book.Title); // requires a variable

24
「変数をプロパティに変更することは、重大な変更です。」もちろんこれは、ほとんどの開発者が行っていない再利用可能なライブラリを作成する場合にのみ適用されます。
スティーブン

30
また、プロパティは、自動プロパティでさえも仮想にすることができますが、フィールドはできません。したがって、派生クラスは追加の検証やその他のロジック/計算を実行できますが、基本クラスは、auto-propのコンパイラーによって生成された単純なバッキングフィールド実装を持つことができます。
KeithS 2013年

28
また、フィールドは変数であり、参照(refまたはoutキーワード)で渡すことができますが、プロパティはアクセサのペアであり、参照で渡すことはできません。たとえば、bool success = TryGetMyTitle(out myBook.Title);を使用outすると、フィールドでは機能し、プロパティでは機能しません。これは、フィールドからプロパティへの変更が重大な変更である理由の明確な例です!
Jeppe Stig Nielsen 2013

2
@KyleBaranいいえ、プロパティは変数ではなく、アクセサメソッドのペアであるため、あまり意味がありません。通常行うことは、ローカル変数を宣言し(場合によってはプロパティを読み取り、その値をローカル変数に入れる)、ローカル変数をref/ として渡しout、プロパティをローカル変数が持つ値に設定します。ただし、呼び出されたメソッド自体はプロパティにアクセスせず、そこで作成したローカル変数にアクセスします。
Jeppe Stig Nielsen 2013

5
@theberserker True、ただしC#6 public int Foo { get; }では読み取り専用のバッキングフィールドを持つ自動プロパティを作成できます。
Michael Stum

83

APIの問題を無視すると、プロパティの使用に関して最も価値があると思うのはデバッグです。

CLRデバッガーはデータブレークポイントをサポートしていません(ほとんどのネイティブデバッガーはサポートしています)。したがって、クラスの特定のフィールドの読み取りまたは書き込みにブレークポイントを設定することはできません。これは、特定のデバッグシナリオでは非常に制限されています。

プロパティは非常に薄いメソッドとして実装されるため、値の読み取りと書き込みにブレークポイントを設定することが可能です。これは彼らにフィールドの上に大きな足を与えます。


2
10年後、少なくとも.NET Coreのデータブレークポイントがここにあります:)
Luaan

72

フィールドからプロパティに変更すると、契約が破られます(たとえば、すべての参照コードを再コンパイルする必要があります)。したがって、他のクラス(パブリック(および一般に保護された)メンバー)との相互作用ポイントがある場合、将来の成長を計画する必要があります。常にプロパティを使用してください。

今日それを自動プロパティにするのは何の意味もありません。3か月後には、それを遅延ロードにしたいことに気づき、ゲッターにnullチェックを入れます。フィールドを使用していた場合、これは再コンパイルの変更であり、アセンブリに依存している人やものに応じて、最悪の場合は不可能です。


9
この回答は、「リフレクション」、「インターフェース」、「オーバーライド」という言葉を使用していないため、気に入りました。(「契約」についてはあまりにも悪い)

65

誰もそれを言及しなかったからといって、インターフェースでフィールドを定義することはできません。したがって、プロパティを定義する特定のインターフェイスを実装する必要がある場合、自動プロパティは非常に優れた機能になることがあります。


1
プロパティを定義するインターフェイスが必要な場合は、抽象クラスである必要があります。c#でインターフェイスのプロパティを定義できるからといって、それらを使用する必要があるわけではありません。悪いデザインです。
Odys '28 / 07/28

8
@odyodyodys-これが悪いデザインであることに私は同意しません。根拠を説明してください。
Zaid Masud

4
@odyodyodys私はzooone9243に同意します。インプ、設計の観点からは、プロパティの宣言とゲッター/セッターのペアの宣言に違いはありません(これはインターフェイスの一般的な方法です)。
MartinStettner

22
@ zooone9243、+ MartinStettner:それは6か月前で、それ以来多くのことを学びました。私はそれを取り戻します:)
Odys

47

見過ごされがちで、他の回答では言及されていない大きな違い:オーバーライド。プロパティを仮想宣言してオーバーライドすることができますが、パブリックメンバーフィールドに対して同じことはできません。


10

バージョン管理とAPIの安定性がすべてです。バージョン1でも違いはありませんが、バージョン2でこれを何らかのタイプのエラーチェックを備えたプロパティにする必要があると判断した場合、APIを変更する必要はありません。プロパティの定義。


10

パブリックフィールドに対する自動実装プロパティのもう1つの利点は、セットアクセサーをプライベートまたは保護にして、パブリックフィールドのコントロールよりも優れたコントロールが定義されたオブジェクトのクラスを提供できることです。


8

フィールドを作ることに問題はありませんpublic。ただしgetter/setterprivateフィールドでの作成はカプセル化ではないことを覚えておいてください。IMO、の他の機能を気にしない場合は、Property作成することもできますpublic


1

後でタイトルが一意であることを確認する場合は、コレクションまたはデータベースと比較することにより、それに依存するコードを変更せずにプロパティで行うことができます。

パブリック属性だけを使用すると、柔軟性が低下します。

コントラクトを壊さない追加の柔軟性は、プロパティの使用に関して私にとって最も重要なものであり、実際に柔軟性が必要になるまで、自動生成が最も理にかなっています。


0

すべてのコードとテストの理由と同様に、私が非常に役立つと思うことの1つは、それがプロパティ対フィールドの場合、Visual Studio IDEはフィールドではなくプロパティの参照を表示するということです。


0

私のハメ撮りはいくつかの研究をした後

  1. 検証。
  2. アクセサーをオーバーライドして、プロパティの動作を変更できるようにします。
  3. デバッグ目的。アクセサーにブレークポイントを設定することで、いつ、何がプロパティが変化するかを知ることができます。
  4. フィールドはセットのみにすることができます。たとえば、public set()およびprivate get()。これはpublicフィールドでは不可能です。

それは本当に私たちにより多くの可能性と拡張性を与えます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.