C#3.0以降のプロパティとフィールドの違い


140

C#のフィールドとプロパティの違い何ですか?しかし、私の質問には(私の観点から)若干の違いがあります:

それを知ったら

  • 「プロパティでのみ機能するテクニック」ではクラスを使用しません。
  • ゲッター/セッターでは検証コードを使用しません。

プロパティの設定におけるある種の制御のように、(スタイル/将来の開発のものを除いて)何か違いはありますか?

間に追加の違いはありますか:

public string MyString { get; set; }

そして

public string myString;

(最初のバージョンではC#3.0以降が必要であり、コンパイラーがプライベートフィールドを作成することを認識しています。)


回答:


117

カプセル化。

2番目のインスタンスでは変数を定義しました。最初のインスタンスでは、変数の周りにゲッター/セッターがあります。したがって、後日変数を検証する場合は、はるかに簡単になります。

さらに、Intellisenseでは表示が異なります:)

編集: OPの更新された質問の更新-ここで他の提案を無視したい場合、他の理由は、それが単にOOのデザインが良くないことです。そして、それを行う十分な理由がない場合は、常にパブリック変数/フィールドではなくプロパティを選択してください。


9
なぜそれが簡単になるのですか?フィールドをプロパティにしてプライベートバッキングフィールドを追加できないのはなぜですか?これは呼び出しコードにどのように影響しますか?
Serge Wautier 2009年

30
@Serge-コンパイル済みのコードに影響します。たとえば、複数のアプリケーションで使用されるライブラリを開発している場合、フィールドをそのライブラリのプロパティに変更するには、各アプリケーションの再コンパイルが必要になります。プロパティの場合、心配することなくプロパティを更新できます。
ダスティンキャンベル

私はあなたに完全に同意します。私は常にプロパティを使用します。考えられる違いに興味がありました
p4bl0 2009年

24
消費コードが影響を受けるクラスと同時に常に再コンパイルされる場合(内部が見えないプライベートまたは内部は100%安全です)、それをフィールドにしても問題はあり
ません

1
すごいあなたのコメントは私が探していた答えです!
p4bl0 2009年

160

フィールドとプロパティは同じに見えますが、同じではありません。プロパティはメソッドであるため、プロパティでサポートされていないものや、プロパティで発生する可能性があるがフィールドの場合には発生しないものがあります。

ここに違いのリストがあります:

  • フィールドは、out/ref引数への入力として使用できます。プロパティはできません。
  • 複数回呼び出された場合、フィールドは常に同じ結果になります(複数のスレッドの問題を除外した場合)。などのプロパティDateTime.Nowは、常にそれ自体と等しいわけではありません。
  • プロパティは例外をスローする場合があります-フィールドはそれを行うことはありません。
  • プロパティには副作用があるか、実行に非常に長い時間がかかる場合があります。フィールドには副作用がなく、常に指定されたタイプで期待できる限り高速になります。
  • プロパティはゲッター/セッターのさまざまなアクセシビリティをサポートしています-フィールドはサポートしていません(ただし、フィールドは作成できますreadonly
  • リフレクションを使用したときの特性とフィールドは異なるように処理されMemberTypes、それらが異なって配置されるように(GetFieldsVS GetProperties例えば)
  • JITコンパイラは、フィールドアクセスと比較してプロパティアクセスを非常に異なる方法で処理する場合があります。ただし、同じネイティブコードにコンパイルされる場合がありますが、違いの範囲はあります。

11
ただし、適切な方法が採用されている場合、これらのポイントのいくつかは違いではないことに注意してください。つまり、プロパティには実際に副作用があってはならず、実行に長い時間がかかるべきではありません。
Noldorin 2012年

15
@Noldorin:私は同意するが、残念ながらすべきは、ここでのキーワードです。フィールドでは、その動作が保証されています。フィールドを使用するべきだと言っているのではありませんが、意味の違いに注意することが重要です。
Brian Rasmussen 2012年

4
ええ、十分に公正です。初心者プログラマーは、残念ながらこれらのことについて手がかりをしばしば持っていません...
Noldorin

2
また、フィールドにはフィールド初期化子があり、プロパティはコンストラクターで初期化する必要があります。
Dio F

3
この答えは、受け入れられた答えよりもはるかに優れていると思います。フィールドよりも常にプロパティを優先する「許容できる」方法は悪い考えだと私は考え始めています。データのみを処理する必要がある場合は、フィールドを使用します。データに機能を適用する必要がある場合は、メソッドを使用します。プロパティには気づかない副作用がある可能性があるため(特に、ライブラリを設計しておらず、ドキュメントがほとんどない場合)、ほとんどの場合、私には直観に反するように見えます。
David Peterson

41

いくつかの明白な違い

  1. プロパティはアクセサキーワードを持つことができます。

    public string MyString { get; private set; }
  2. 子孫でプロパティをオーバーライドできます。

    public virtual string MyString { get; protected set; }

1
mmh .. nr 2はおもしろい..考えなかった
p4bl0 2009年

14

基本的な違いは、フィールドは、指定されたタイプのデータが格納されるメモリ内の位置であることです。プロパティは、指定されたタイプの値を取得または設定するために実行されるコードの1つまたは2つの単位を表します。これらのアクセサーメソッドの使用は、フィールドのように動作するように見えるメンバー(割り当て操作のどちらの側にも表示できる)を使用することにより、構文的に隠されています。


11

アクセサはフィールド以上のものです。他の人はすでにいくつかの重要な違いを指摘しているので、もう1つ追加します。

プロパティはインターフェイスクラスに参加します。例えば:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

このインターフェースは、いくつかの方法で満たすことができます。例えば:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

この実装では、両方を保護しています Personクラスが無効な状態になること、および呼び出し側が割り当てられていないプロパティからnullを取得するからしています。

しかし、デザインをさらに推し進めることができます。たとえば、インターフェイスはセッターを処理しない場合があります。IPersonインターフェースの消費者は、プロパティを設定するのではなく、プロパティを取得することにのみ関心があると言うのはかなり正当です。

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

Personクラスの以前の実装はこのインターフェースを満たしています。呼び出し側もプロパティを設定できるという事実は、消費者(消費者)の観点からは無意味IPersonです。具体的な実装の追加機能は、たとえばビルダーによって考慮されます。

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

このコードでは、消費者はプロパティセッターについて知らない-それについて知ることは彼のビジネスではない。消費者はゲッターを必要とするだけで、インターフェースから、つまり契約からゲッターを取得します。

のもう1つの完全に有効な実装はIPerson、不変のpersonクラスと対応するpersonファクトリです。

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

このコードサンプルでは、​​コンシューマはプロパティを埋める知識がありません。コンシューマーはゲッターと具体的な実装(およびその背後にあるビジネスロジック(名前が空かどうかのテストなど)のみを処理します)は、専門のクラス(ビルダーとファクトリー)に任されています。これらの操作はすべてフィールドでは不可能です。


7

最初の1つ:

public string MyString {get; set; }

プロパティです。2番目(public string MyString)はフィールドを示します。

違いは、特定の手法(インスタンスのASP.NETデータバインディング)はプロパティに対してのみ機能し、フィールドに対しては機能しないことです。XMLシリアル化についても同様です。プロパティのみがシリアル化され、フィールドはシリアル化されません。


8
違う。XMLシリアル化は、パブリックフィールドをシリアル化します。
セルジュウォティエ2009年

2
多分。ただし、クラスからオブジェクトデータソースを作成すると、フィールドではなくプロパティのみを使用できます。(私が何か間違ったことをしなかった場合を除いて:P)
ヴィッシュ

良いのはDRYです;)ですが、もう一度書きます。C#言語でのプロパティの強力な役割が好きです。Javaに比べて実装がはるかに優れている(結果的に最初から)多くの、おそらくすべての.netソリューションはプロパティでのみ機能します。WPF、ASPXなど。
Jacek Cz

3

プロパティとフィールドは、多くの場合、似ているように見えますが、似ていません。フィールドに存在しないプロパティには制限があり、その逆も同様です。

他の人が述べたように。アクセサーをプライベートにすることで、プロパティを読み取り専用または書き込み専用にすることができます。フィールドでそれを行うことはできません。プロパティは仮想にすることもできますが、フィールドはできません。

プロパティをgetXXX()/ setXXX()関数の構文糖と考えてください。これは、それらが裏で実装されている方法です。


1

フィールドとプロパティの間には、もう1つの重要な違いがあります。

WPFを使用する場合、パブリックプロパティにのみバインドできます。パブリックフィールドへのバインドは機能しません。これは、実装しINotifyPropertyChangedていなくても当てはまります(常にそうする必要があります)。


良いのはDRYです;)ですが、もう一度書きます。C#言語でのプロパティの強力な役割が好きです。Javaに比べて実装がはるかに優れている(結果的に最初から)多くの、おそらくすべての.netソリューションはプロパティでのみ機能します。WPF、ASPXなど。
Jacek Cz

1

他の回答や例の中で、この例はいくつかの状況で役立つと思います。

たとえば、次のようなものがあるとします。OnChange property

public Action OnChange { get; set; }

あなたは、あなたがそれを変更する必要があるよりも、デリゲートを使用する場合OnChangefield、このように:

public event Action OnChange = delegate {};

このような状況では、不要なアクセスや変更からフィールドを保護します。


0

パブリックフィールドには、常にフィールドではなくプロパティを使用する必要があります。これにより、将来必要になる場合に、既存のコードを壊すことなく、ライブラリがフィールドのカプセル化を実装できるようになります。フィールドを既存のライブラリのプロパティに置き換えると、すべてのライブラリを使用する依存モジュールも再構築する必要があります。


「常に」というのは難しい言葉です。C#では(Javaよりも優れています)プロパティは強い位置にあり、(おそらく例外なく)メイン、ASP、WPFなどの「バインディング」のメソッドです。しかし、それにもかかわらず、私は、フィールドでのデザインは何の財産であることが意味(時々 )は想像もできない
ヤツェクのCz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.