web-dev-qa-db-ja.com

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

私はそれが C#のフィールドとプロパティの違いは何ですか? の複製のように思えますが、私の質問にはわずかな違いがあります(私の観点から):

それを知ったら

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

プロパティを設定する際のある種のコントロールのように、違いはありますか(スタイル/将来の開発のものを除く)?

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

public string MyString { get; set; }

そして

public string myString;

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

137
p4bl0

カプセル化。

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

さらに、IntelliSenseでの表示も異なります。

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

115
Mark Ingram

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

違いのリストは次のとおりです。

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

いくつかの簡単な明らかな違い

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

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

    public virtual string MyString { get; protected set; }
    
41
Dustin Campbell

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

14
AnthonyWJones

アクセサはフィールド以上のものです。他の人はすでにいくつかの重要な違いを指摘しており、もう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);
}

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

IPersonの別の完全に有効な実装は、不変の個人クラスと対応する個人ファクトリーです。

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);
}

このコードのサンプルコンシューマでは、再びプロパティを入力する知識がありません。消費者はゲッターと具体的な実装(およびその背後にあるビジネスロジック(名前が空であるかどうかのテストなど)のみを扱う)は、特殊なクラス(ビルダーと工場)に任されています。これらの操作はすべて、フィールドではまったく不可能です。

11
Zoran Horvat

最初の1つ:

public string MyString {get; set; }

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

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

7

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

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

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

3

他の回答と例の中でも、この例は状況によっては役立つと思います。

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

public Action OnChange { get; set; }

デリゲートを使用する場合は、次のように変更する必要がありますOnChange to field

public event Action OnChange = delegate {};

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

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

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

1
BradleyDotNET

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

0
user1849310