フィールドとプロパティの違いは何ですか?


1130

C#では、フィールドとプロパティの違いは何ですか。また、プロパティの代わりにフィールドを使用する必要があるのはいつですか。


32
Microsoftは、(すべての.NET言語に対して)メンバーデザインガイドラインの一部としてこの質問に直接回答しています。詳細については、「プロパティデザイン」および「フィールドデザイン」の記事を参照してください。インスタンスメンバーと静的メンバーには違いがあることに注意してください。
DavidRR

回答:


979

プロパティはフィールドを公開します。フィールドは(ほとんどの場合)クラスに対してプライベートにして、getおよびsetプロパティを介してアクセスする必要があります。プロパティは、クラスを使用するものからアクセスされる外部の方法に影響を与えずにフィールドを変更できるようにする抽象化のレベルを提供します。

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kentは、プロパティはフィールドをカプセル化する必要はなく、他のフィールドで計算を行ったり、他の目的に役立つ可能性があることを指摘しています。

@GSSは、プロパティにアクセスしたときに検証などの他のロジックを実行できることも指摘しています。これは別の便利な機能です。


185
プロパティをフィールドをカプセル化するために必要としないことは注目に値します。プロパティの背後にフィールドがまったくない場合もあります。それは計算かもしれないし、定数か何かを返すかもしれません。
Kent Boogaart 2008年

9
「一方で、クラスを使用するものからアクセスする外部の方法には影響しません。」私が誤って理解している場合は許してください、しかし、なぜその後ろのフィールドがこれを処理するように見えるのに、なぜプロパティの前にアクセス修飾子が必要なのですか?つまり、なぜプロパティをパブリック以外のものにするのですか?
チャッキー、

18
あなたの答えは編集の直前であり、奇妙なことに間違ったコメントが付けられました。プロパティは常に1つ以上のフィールドをカプセル化する必要があり、重い処理や検証を行わないでください。検証のためにUserNameやPasswordなどのプロパティが必要な場合は、それらのタイプを文字列から値オブジェクトに変更します。クラス作成者と消費者の間には暗黙の契約があります。フィールドは状態を保持し、プロパティは1つ以上のフィールドを使用して状態を公開し、ボイドは状態を変更し(重いリフティング)、関数はクエリを実行します(重いリフティング)。
Suamere 2015年

6
@jpaugh私がクラスの消費者である場合、私はクラスの作成者が設定した契約に従います。プロパティがstringである場合、私の契約は、最大20億文字までの文字を割り当てることです。プロパティがの場合DateTime、私の契約は、DateTimeの制限内の任意の数値を割り当てます。作成者が制約をセッターに追加した場合、それらの制約は伝達されません。ただし、代わりに、作成者が型をからstringに変更したSurname場合、新しいSurnameクラスが制約を伝え、プロパティpublic Surname LastNameはセッター検証を行いません。また、Surname再利用可能です。
Suamere 2017

4
また、Surname私の例ではは再利用可能なため、プロパティセッターの検証をコード内の他の場所にコピー/貼り付けるときに心配する必要はありません。姓のビジネスルールに変更を加えた場合でも、姓の検証が複数の場所にあるかどうかも疑問に思いません。Value Objectsについて投稿したリンクをチェックする
Suamere

261

オブジェクト指向プログラミングの原則によると、クラスの内部動作は外部の世界から隠されるべきです。フィールドを公開すると、本質的にはクラスの内部実装が公開されます。したがって、フィールドをプロパティ(またはJavaの場合はメソッド)でラップして、コードを壊さずに実装を変更できるようにします。プロパティにロジックを配置できるので、必要に応じて検証ロジックなどを実行できます。C#3には、自動プロパティのわかりにくい概念があります。これにより、プロパティを定義するだけで済み、C#3コンパイラはプライベートフィールドを生成します。

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}

89
オートプロパティについて言及するための+1-これは、ここ(および他の場所)で持ち込んだ答えの多くが忘れているものだと思います。この説明がないと、public int myVar { get; set; }実際には何を表しているのかを理解するのがかなり難しい場合があります(それが理由だと思います)少なくとも50%のヒットがこの質問で取得されます)。
Priidu Neemre 2013年

7
+1は、autoについて言及し、その動作についても言及しました(「AutoPropertyは私たちのためにプライベートフィールドを生成します」)これは、私が探していた質問に対する回答でした。調査したところ、MSDNのページにそれらについては表示されませんでした。プライベートフィールドが作成され、混乱を引き起こしているという兆候はありませんでした。これはどういう意味だと思いますか?「属性は、自動実装されたプロパティでは許可されていますが、ソースコードからアクセスできないため、バッキングフィールドでは許可されていません。プロパティのバッキングフィールドで属性を使用する必要がある場合は、通常のプロパティを作成してください。」確かではありませんでした。
Nyra

3
与えられた例はスクワットをカプセル化しないことに注意してください。このプロパティは、プライベートフィールドへの100%のフルアクセスを提供するため、オブジェクト指向ではありません。この場合、パブリックフィールドを使用することもできます。確かに、それは将来的にコードをリファクタリングするのに(わずかに)役立ちますが、適度な価値のあるIDEであれば、いくつかのキーストロークでフィールドをプロパティに変換できます。プロパティがどのように機能するかについては、技術的には正しい答えかもしれませんが、それはそれらの使用法についての「OOPの説明」にはなりません。
サラ2016

2
@kai答えは単純化しすぎて自動プロパティのすべての力を示していないことに同意しますが、これはオブジェクト指向ではないことに同意しません。フィールドとプロパティの違い確認することもできます。フィールドは仮想にすることはできず、virtualそれ自体がオブジェクト指向プログラミングの一部です。
Gobe 2016

確かに、いくつかの機能的な違いがあります。私はvirtualそれ自体はOOP とは呼びません。これは、ポリモーフィズムを可能にするツールであり、OOPを有効にする主要なツールの1つです。ただし、それ自体はOOPではなく、公開の自動プロパティについて本質的にOOPはありません。リフレクションやOOP関連のデータバインディングなども考慮しません。通常、私はそれについてそれほど面倒ではありませんが、答えはコード例の背後にある原動力としてOOの原則を具体的に言及しており、私はそれに同意しません。
サラ2016

164

重要な違いは、インターフェイスはプロパティを持つことができますが、フィールドを持つことはできません。私にとって、これは、クラスのパブリックインターフェイスを定義するためにプロパティを使用する必要があることを強調していますが、フィールドは、クラスのプライベートな内部動作で使用するためのものです。原則として、パブリックフィールドを作成することはほとんどなく、同様に、非パブリックプロパティを作成することはほとんどありません。


98

ギアを回転させる可能性のあるプロパティの使用例をいくつか紹介します。

  • 遅延初期化オブジェクトのプロパティを読み込むのにコストがかかるが、通常のコードの実行ではそれほどアクセスされない場合は、プロパティを介してオブジェクトの読み込みを遅らせることができます。そのようにして、そこに座っているだけですが、別のモジュールがそのプロパティを初めて呼び出そうとするときに、基になるフィールドがnullかどうかをチェックします。これにより、オブジェクトの初期化を大幅に高速化できます。
  • ダーティトラッキング: StackOverflow に関する自身の質問から実際に学んだことです。実行中に値が変更された可能性のあるオブジェクトが多数ある場合は、プロパティを使用して、データベースに保存する必要があるかどうかを追跡できます。オブジェクトの単一のプロパティが変更されていない場合、IsDirtyフラグは作動しないため、データベースに戻す必要があるものを決定するときに、保存機能はそれをスキップします。

1
ダーティートラッキングに関する質問:フィールドを直接変更できるとしたら–それが可能かどうかわからないので、「オブジェクトの単一のFIELDが変更されていない場合、オブジェクトを保存する必要はありません」したがって、ダーティトラッキングは違いになりませんが、何か不足していますか?
サイト

2
@juanpastas:ダーティトラッキングに関するプロパティの利点は、プロパティセッターが「ダーティ」フラグを設定する場合、フラグが設定されていないシナリオでは、コードがプロパティの値を調べて確認する必要がないことです。それらが変更された可能性がある場合。オブジェクトがフィールドとしてその属性を公開する場合は対照的に、すべてのフィールドの内容は、(比較を行うための時間を追加するだけでなく、コードがなければならないことを意味するだけでなく、以前の値と比較する必要があります持っている前回値)。
スーパーキャット2013年

それらは良いものです。また、値を設定または読み取ったときに、メソッドを(イベントとして)トリガーしたり、ログに記録したりできます。
coloboxp

54

プロパティを使用すると、プロパティの値が変更されたとき(別名PropertyChangedEvent)、またはキャンセルをサポートするために値が変更される前に、イベントを発生させることができます。

これは(直接アクセス)フィールドでは不可能です。

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}

3
これを見つけるのに長い時間がかかりました。これはMVVMです。ありがとうございました !:)

46

それらの多くは、技術の長所と短所を説明してきたPropertiesし、Fieldそれがリアルタイム例に取得する時間です。

1.プロパティにより、読み取り専用アクセスレベルを設定できます

ケースを考えてみましょうdataTable.Rows.CountdataTable.Columns[i].Caption。彼らはクラスから来て、DataTable両方とも私たちに公開されています。それらに対するアクセスレベルの違いは、値をに設定することはできませんdataTable.Rows.Countが、への読み取りと書き込みは可能dataTable.Columns[i].Captionです。それは可能Fieldですか?番号!!!これはPropertiesのみで行うことができます。

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. PropertyGridのプロパティ

ButtonVisual Studioで作業した可能性があります。そのプロパティは「いいPropertyGridTextNameなどで表示されます。ボタンをドラッグアンドドロップすると、プロパティをクリックするButtonと、クラスとフィルターが自動的に検出されてProperties表示されますPropertyGrid(パブリックであってもPropertyGrid表示されませんField)。

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

ではPropertyGrid、プロパティNameTextが表示されますが、は表示されませんSomeProperty。なぜ???プロパティは属性を受け入れることができるからです。[Browsable(false)]がfalseの場合は表示されません。

3.プロパティ内でステートメントを実行できます

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4.バインディングソースで使用できるのはプロパティのみです

ソースのバインドは、コードの行数を減らすのに役立ちます。Fieldsは受け入れませんBindingSource。そのために使用する必要がありますProperties

5.デバッグモード

Field値の保持に使用していると考えてください。ある時点で、そのフィールドの値がnullになる場所をデバッグして確認する必要があります。コードの行数が1000を超える場所で行うのは困難です。このような状況ではProperty、内でデバッグモードを使用および設定できますProperty

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }

これらは興味深い事実ですが、フィールドとプロパティの哲学のポイントを逃しています。
David FerenczyRogožan15年

PHILISOPHYとはどういう意味ですか?@Dawid Ferenczy
Sarath Avanavu 2015年

たとえば、マークされた回答を参照してください。しかし、あなたはあなたがちょうどすでに説明したフィールドとプロパティの違いから、使用例を提供していることに、気づいたので、私のコメントを忘れてしまった、してください:)
デビッドFerenczyRogožan

2
私の答えの最初の文を読んでください。私はここで再びすべてを繰り返すつもりはないことを明確に述べました。それは意味がありません!!! 人々は最初に説明を最初に見て、次に例を見ます。マークされた答えは説明をよく示していますが、私はいくつかのリアルタイムのシナリオと意味のある例を追加しました。@Dawid Ferenczyにコメントする前に、読者の視点から考えてください
Sarath Avanavu

1
私はそれを読みましたが、私の以前のコメントは明らかに読んでいませんでした:「しかし、フィールドとプロパティの違いがすでに説明されているため、使用例を提供しているだけであることに気付いたので、コメントを忘れてください:)」 。
David FerenczyRogožan15年

32

相違点-用途(時期と理由)

フィールドは、クラスまたは構造体で直接宣言された変数です。クラスまたは構造体は、インスタンスフィールドまたは静的フィールド、あるいはその両方を持つことができます。通常、フィールドは、プライベートまたは保護されたアクセシビリティを持つ変数に対してのみ使用する必要があります。クラスがクライアントコードに公開するデータは、メソッド、プロパティ、インデクサーを通じて提供する必要があります。これらの構成体を使用して内部フィールドに間接的にアクセスすることにより、無効な入力値を防ぐことができます。

プロパティは、読み取り、書き込み、またはプライベートフィールドの値を計算するための柔軟なメカニズムを提供する部材です。プロパティは、パブリックデータメンバーのように使用できますが、実際にはアクセサーと呼ばれる特別なメソッドです。これにより、データへのアクセスが容易になり、メソッドの安全性と柔軟性が向上します。プロパティを使用すると、実装や検証コードを隠しながら、クラスが値を取得および設定するパブリックな方法を公開できます。getプロパティアクセサーはプロパティ値を返すために使用され、setアクセサーは新しい値を割り当てるために使用されます。


これは素晴らしい答えです。これを理解するのに本当に役立ちました。
スティーブバウマン2018

14

プロパティには、オブジェクトのパブリックインターフェイスを壊すことなく、オブジェクトのデータへのアクセス方法を変更できるという主な利点があります。たとえば、追加の検証を追加する必要がある場合、または格納されたフィールドを計算済みフィールドに変更する必要がある場合、最初にフィールドをプロパティとして公開しておけば簡単に行うことができます。フィールドを直接公開した場合は、クラスのパブリックインターフェイスを変更して新しい機能を追加する必要があります。その変更は既存のクライアントを破壊し、新しいバージョンのコードを使用する前に再コンパイルする必要があります。

何百万人ものユーザーが使用する.NET Frameworkのように、広く利用できるように設計されたクラスライブラリを作成すると、問題が発生する可能性があります。ただし、小さなコードベース内で内部的に使用されるクラス(たとえば、50 K行以下)を記述している場合、変更によって悪影響を受けることはないため、それほど大きな問題ではありません。その場合、それは本当に個人的な好みに帰着します。


11

プロパティは非対称アクセスをサポートします。つまり、ゲッターとセッターのいずれか、または2つのうちの1つだけを持つことができます。同様に、プロパティはゲッター/セッターの個々のアクセシビリティをサポートします。フィールドは常に対称です。つまり、常に値を取得および設定できます。これの例外は、初期化後に明らかに設定できない読み取り専用フィールドです。

プロパティは非常に長い時間実行され、副作用があり、例外をスローすることさえあります。フィールドは高速で、副作用はなく、例外をスローすることはありません。副作用のため、プロパティは呼び出しごとに異なる値を返す場合があります(DateTime.Nowの場合と同様に、DateTime.Nowが常にDateTime.Nowと等しいとは限りません)。フィールドは常に同じ値を返します。

フィールドはout / refパラメータに使用できますが、プロパティは使用できません。プロパティは追加のロジックをサポートしています。これは、とりわけ遅延読み込みを実装するために使用できます。

プロパティは、値を取得/設定することを意味するものをカプセル化することにより、抽象化のレベルをサポートします。

ほとんどの場合/すべての場合にプロパティを使用しますが、副作用を回避するようにしてください。


フィールドのデータ型が変換演算子のオーバーロードを持つオブジェクトである場合、フィールドにはすべてのプロパティのコストの問題がある可能性があります。これは微妙な問題です。
アンディ・デント

1
プロパティに副作用があってはなりません。デバッガでさえ、それらを安全に評価できると想定しています。
Craig Gidney、

@Strilanc:私は完全に同意しますが、常にそうであるとは限りません。デバッガに関しては、それがあなたが話しているものである場合、FuncEvalには多くの問題があります。
ブライアンラスムッセン

11

バックグラウンドでは、プロパティはメソッドにコンパイルされます。したがって、Nameプロパティはget_Name()およびにコンパイルされset_Name(string value)ます。これは、コンパイルされたコードを調べるとわかります。そのため、これらを使用すると、(非常に)小さなパフォーマンスオーバーヘッドが発生します。通常、フィールドを外部に公開する場合は常にプロパティを使用し、値の検証を行う必要がある場合はプロパティを内部で使用することがよくあります。


7

プライベート変数(フィールド)を他のクラスからクラスのオブジェクトにアクセスできるようにするには、それらの変数のプロパティを作成する必要があります。

たとえば、「id」および「name」という名前の変数がプライベートであるが、この変数がクラス外での読み取り/書き込み操作に必要な場合があります。その状況では、プロパティは、プロパティに定義されたget / setに応じて、その変数を読み取り/書き込みできるようにするのに役立ちます。プロパティは、読み取り専用/書き込み専用/読み取り/書き込みの両方にすることができます。

ここにデモがあります

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}

6

ここの2番目の質問「プロパティの代わりにフィールドを使用する必要があるのはいつですか?」は、 、この他の答えとちょっとあまりにもこの1ではなく、本当に多くのディテール。

一般に、他のすべての答えは、優れた設計に関するスポットオンです。フィールドを公開するよりもプロパティを公開することを優先します。あなたはおそらくしませんが、定期的に自分で言って見つけるそれはだ、「うわー、私が代わりにプロパティのこのフィールドを作っていた場合でしょうかずっと悪い事を想像」そんなに、あなたはすごい」と言うだろうな状況を考えると、より珍しいです神様に感謝します。ここではプロパティの代わりにフィールドを使用しました。」

ただし、フィールドにはプロパティよりも優れている点が1つあります。それは、「ref」/「out」パラメーターとして使用できることです。次のシグネチャを持つメソッドがあるとします。

public void TransformPoint(ref double x, ref double y);

そのメソッドを使用して、次のように作成された配列を変換するとします。

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

XYなので、これを行うには最速の方法だと思いますはプロパティます。

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

そして、それはかなり良いことになるでしょう!他に証明できる測定値がない限り、悪臭を放つ理由はありません。しかし、技術的にこれほど高速であるとは保証されていません。

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

いくつかやって 自分で測定をと、フィールドを含むバージョンは、プロパティを含むバージョン(.NET 4.6、Windows 7、x64、リリースモード、デバッガーが接続されていないバージョン)と比べて約61%の時間を要します。TransformPointメソッドが高価になるほど、違いがはっきりしなくなります。これを自分で繰り返すには、最初の行をコメントアウトして実行し、コメントアウトしないで実行します。

上記のパフォーマンス上の利点がなかったとしても、InterlockedまたはVolatileファミリのメソッドを呼び出す場合など、refおよびoutパラメータを使用できることが有益である他の場所があります。 注:これが初めての場合、Volatileは基本的に、volatileキーワードです。そのため、のようにvolatile、その名前が示すとおり、すべてのスレッドセーフティの問題を魔法のように解決するわけではありません。

「ああ、私はプロパティの代わりにフィールドを公開し始めるべきだ」と言っているように私が絶対に思われたくない。重要なのは、「ref」または「out」パラメーターを取る呼び出しでこれらのメンバーを定期的に使用する必要がある場合、特に、プロパティの値が追加された要素が必要になる可能性が低い単純な値型である可能性がある場合です。議論をすることができます。


6

フィールドとプロパティは互いに似ているように見えますが、2つの完全に異なる言語要素です。

  1. フィールドは、クラスレベルでデータを格納する唯一のメカニズムです。フィールドは、概念的にはクラススコープの変数です。クラス(オブジェクト)のインスタンスにデータを格納する場合は、フィールドを使用する必要があります。他に選択肢はありません。プロパティはデータを格納できませんが、格納できるように見える場合があります。下記をご覧ください。

  2. 一方、プロパティはデータを格納しません。これらはメソッドのペア(getとset)であり、構文的にはフィールドと同じように呼び出すことができ、ほとんどの場合、フィールドにアクセス(読み取りまたは書き込み)するため、混乱が生じます。ただし、プロパティメソッドは(固定プロトタイプのようないくつかの制限があります)通常のC#メソッドであるため、通常のメソッドと同じように実行できます。つまり、1000行のコードを持つことができ、例外をスローしたり、別のメソッドを呼び出したり、仮想、抽象、またはオーバーライドすることもできます。プロパティが特別なのは、C#コンパイラが、特定のプロパティ(広く使用されている機能)を検索するために使用できる追加のメタデータをアセンブリに格納することです。

プロパティメソッドの取得と設定には、次のプロトタイプがあります。

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

つまり、フィールドと2つの対応するメソッドを定義することで、プロパティを「エミュレート」できるということです。

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

このようなプロパティエミュレーションは、標準のC ++のように、プロパティをサポートしないプログラミング言語では一般的です。C#では、フィールドへのアクセス方法として常にプロパティを優先する必要があります。

フィールドだけがデータを格納できるため、より多くのフィールドクラスが含まれ、そのようなクラスのより多くのメモリオブジェクトが消費します。一方、クラスに新しいプロパティを追加しても、そのようなクラスのオブジェクトは大きくなりません。以下がその例です。

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

プロパティメソッドは何でも実行できますが、ほとんどの場合、オブジェクトのフィールドにアクセスする方法として機能します。フィールドを他のクラスからアクセス可能にする場合は、2つの方法で行うことができます。

  1. フィールドを公開にする-推奨されません。
  2. プロパティの使用。

以下はpublicフィールドを使用するクラスです。

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

コードは完全に有効ですが、設計の観点からは、いくつかの欠点があります。フィールドは読み取りと書き込みの両方が可能なため、ユーザーがフィールドに書き込むことを防ぐことはできません。readonlyキーワードを適用できますが、この方法では、コンストラクターでのみ読み取り専用フィールドを初期化する必要があります。さらに、無効な値をフィールドに格納することを妨げるものは何もありません。

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

コードは有効です。それらは非論理的ですが、すべての割り当てが実行されます。Age負の値があり、YearOfBirth遠い将来であり、年齢に対応せず、FullNamenullです。フィールドを使用するとclass Name、ユーザーがそのような間違いを犯すのを防ぐことはできません。

これらの問題を修正するプロパティを含むコードを次に示します。

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

クラスの更新バージョンには、次の利点があります。

  1. FullNameそして、YearOfBirth無効な値がチェックされています。
  2. Age書き込み不可です。それはYearOfBirth、現在の年ます。
  3. 新しいプロパティは大文字にFullNameInUppercase変換さFullNameれます。これは、プロパティの使用法の少し不自然な例です。プロパティは、通常、フィールド値をユーザーにより適した形式で表示するために使用されます-たとえば、特定の数値の数値で現在のロケールを使用しDateTimeます。

これに加えて、プロパティは仮想またはオーバーライドとして定義できます。これは、それらが通常の.NETメソッドであるためです。このようなプロパティメソッドには、通常のメソッドと同じルールが適用されます。

C#は、プロパティメソッドにインデックスパラメーターを持つプロパティであるインデクサーもサポートしています。以下がその例です。

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

C#3.0以降では、自動プロパティを定義できます。以下がその例です。

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

class AutoPropsプロパティのみを含んでいても(またはそのように見えます)、2つの値を格納でき、このクラスのオブジェクトのサイズはsizeof(Value1)+sizeof(Value2) = 4 + 4 = 8バイトです。

この理由は簡単です。自動プロパティを定義すると、C#コンパイラは非表示フィールドと、この非表示フィールドにアクセスするプロパティメソッドを持つプロパティを含む自動コードを生成します。これがコンパイラが生成するコードです。

以下は、コンパイルされたアセンブリからILSpyによって生成されたコードです。クラスには、生成された非表示フィールドとプロパティが含まれています。

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

したがって、ご覧のように、コンパイラはフィールドを使用して値を格納します。フィールドがオブジェクトに値を格納する唯一の方法であるためです。

ご覧のとおり、プロパティとフィールドの使用構文は似ていますが、概念は大きく異なります。自動プロパティまたはイベントを使用する場合でも、非表示フィールドは、実際のデータが格納されるコンパイラーによって生成されます。

フィールド値を外部からアクセスできるようにする必要がある場合(クラスのユーザー)は、パブリックフィールドまたは保護フィールドを使用しないでください。フィールドは常にプライベートとしてマークする必要があります。プロパティを使用すると、値のチェック、書式設定、変換などを行うことができ、一般的にコードをより安全で読みやすく、将来の変更のために拡張することができます。


4

また、プロパティを使用すると、値を設定するときにロジックを使用できます。

したがって、値がxより大きい場合は、整数フィールドに値を設定したいだけであり、そうでない場合は例外をスローします。

本当に便利な機能。


4

スレッドプリミティブを使用する場合は、フィールドを使用する必要があります。プロパティはスレッド化されたコードを壊す可能性があります。それとは別に、コーリーが言ったことは正しいです。


1
いつから?プロパティの中にあなたのバッキングフィールドをロックし、それがequivilantだ
Sekhat

1
プロパティはメソッドであり、現在、CIL JITによってインライン化されていません。Interlockedのようなスレッドプリミティブを使用する場合は、フィールドが必要です。ソースを確認してください。確かに、「ロック」は使用するのに間違った言葉でした。
ジョナサンCディキンソン

4

(これは本当にコメントであるべきですが、コメントを投稿することはできません。投稿として適切でない場合は失礼します)。

私はかつて、次のように、同等のプロパティdefがフィールドにアクセスするだけの場合に、プロパティではなくパブリックフィールドを使用することが推奨されている場所で働いていました。

get { return _afield; }
set { _afield = value; }

彼らの推論は、必要に応じてパブリックフィールドを後でプロパティに変換できる可能性があるというものでした。当時は少し奇妙に思えました。これらの投稿から判断すると、ここではあまり同意しないようです。物事を変えようとするために何を言いましたか?

編集:この場所のすべてのコードベースが同時にコンパイルされたことを追加する必要があります。そのため、(パブリックフィールドをプロパティに変更して)クラスのパブリックインターフェイスを変更することは問題ではないと考えているかもしれません。


以来、C#3.0、パターンは、ここで説明する便利と呼ばれる機能によってサポートされている自動実装プロパティ
DavidRR 2014年

プロパティを使用したC#の利点の1つは、フィールドと同じAPIを持っているため、クラスのクライアントは、プロパティまたはフィールドにアクセスしているかどうかを気にしません。(これは、たとえばC ++では当てはまりません。)プロトタイピングでは、パブリックフィールドから始めて、必要に応じてプロパティに移行するのが妥当だと思います。プロパティにはパフォーマンスとメモリヒットがあり、追加のタイピングがあります。彼らは自由ではありません。ただし、気が変わっても、依存するコードをリファクタリングする必要はありません。
マークラカタ2015年

プロパティはOUTまたはREFパラメーターとして使用できないため、フィールドをプロパティに変更すると、コンパイルエラーが発生する可能性があります。値が最初からプロパティとして実装されていた場合、OUTまたはREF(Pascal / DelphiではVAR)パラメーターとして使用されることはなく、ゲッター/セッターで行った変更は使用法に対して透過的です。
HeartWare、2017年

4

技術的には、プロパティはユーザーが作成したフィールド、またはコンパイラが自動的に作成したフィールドのラッパーにすぎないため、違いはないと思います。プロパティの目的は、カプセル化を強制し、軽量なメソッドのような機能を提供することです。フィールドをパブリックとして宣言するのは単に悪い習慣ですが、問題はありません。


4

フィールドは、通常のメンバー変数またはクラスのメンバーインスタンスです。プロパティは、その値を取得および設定するための抽象概念です。プロパティは、クラス内のフィールドをプライベートとして公開した場合にフィールドを変更および取得する方法を提供するため、アクセサーとも呼ばれます。一般に、メンバー変数をプライベートとして宣言してから、それらのプロパティを宣言または定義する必要があります。

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }

3

プロパティはフィールドをカプセル化するため、設定または取得する値に対して追加の処理を実行できます。フィールド値に対して前処理または後処理を行わない場合は、通常、プロパティを使用するのはやり過ぎです。


1
いいえ、私は常にプロパティを使用しています。これにより、APIを壊すことなく、いつでも実装を柔軟に変更できます。
セハト2008年

APIの進化については、問題なくプライベートデータのフィールドを使用できます。また、アセンブリ内でデータを共有したいという奇妙なケースでは、フィールドに「内部」アクセスを与えることができます。
Daniel Earwicker 2008年

3

IMO、プロパティは、以前使用した "SetXXX()" "GetXXX()"関数/メソッド/インターフェースのペアにすぎませんが、より簡潔でエレガントです。


3

従来、プライベートフィールドは、getterおよびsetterメソッドを介して設定されていました。コードを減らすために、代わりにプロパティを使用してフィールドを設定できます。


3

「車」というクラスがある場合。プロパティは、色、形状です。

フィールドはクラスのスコープ内で定義される変数です。


3

ウィキペディアから- オブジェクト指向プログラミング

オブジェクト指向プログラミング(OOP)は、「オブジェクト」の概念に基づいたプログラミングパラダイムです。これは、属性と呼ばれるフィールドの形でデータを含むデータ構造です。そしてコードは、手順の形で、しばしば方法として知られています(強調を追加)

プロパティは、実際にはオブジェクトの動作の一部ですが、オブジェクトのコンシューマーに、オブジェクトのデータを操作するような錯覚/抽象化を提供するように設計されています。


3

フィールドの私の設計は、フィールドはその親、つまりクラスによってのみ変更する必要があるということです。結果、変数がプライベートになり、外部のクラス/メソッドを読み取る権限を与えることができるように、Getのみでプロパティのシステムを通過します。次に、フィールドはプロパティによって取得され、読み取り専用になります。それを変更したい場合は、メソッド(たとえば、コンストラクター)を実行する必要があります。この方法でセキュリティを確保すると、「フランジ」するため、コードをより適切に制御できるようになります。すべてを常に公開することができるので、可能性のあるすべてのケース、変数/メソッド/クラスなどの概念は...私の意見では、コードの開発、保守の助けにすぎません。たとえば、人がパブリックフィールドでコードを再開した場合、彼は何でもできるため、「非論理的」なことを行うことができます。目的に関連して、コードが書かれた理由のロジック。私の意見です。

クラシックモデルのプライベートフィールド/パブリックの読み取り専用プロパティを使用する場合、10個のプライベートフィールドに対して、10個のパブリックプロパティを記述します。コードは本当に大きくなる可能性があります。私はプライベートセッターを発見し、プライベートセッターでのみパブリックプロパティを使用します。セッターはプライベートフィールドをバックグラウンドで作成します。

それが私の昔の古典的なプログラミングスタイルでした:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

私の新しいプログラミングスタイル:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}

ああ、ごめんなさい!
トニー・ピノ・

3

考えてみてください。あなたはこの部屋に入る部屋とドアを持っています。誰が入ってくるかをチェックして部屋を確保したい場合は、プロパティを使用する必要があります。そうしないと、プロパティがドアにはならず、誰もが規制なしで簡単に入ることができます。

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

人々はsectionOneにかなり簡単に入り始めました、チェックはありませんでした

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

今、あなたは人をチェックして、彼が彼と一緒に何か悪いことをしているかどうか知っています


3

フィールドはクラスの変数です。フィールドは、アクセス修飾子を使用してカプセル化できるデータです。

プロパティは、オブジェクトに関連付けられた状態とデータを定義するという点でフィールドに似ています。

フィールドとは異なり、プロパティには、ユーザーがデータを読み取ったり、データを書き込んだりする方法を制御する特別な構文があります。これらは、取得および設定演算子として知られています。多くの場合、設定ロジックは検証を行うために使用できます。


2

プロパティは、特別な種類のクラスメンバーです。プロパティでは、事前定義されたSetメソッドまたはGetメソッドを使用します。これらは、プライベートフィールドの値を読み取り、書き込み、または変更できるアクセサーを使用します。

たとえばEmployee、名前、年齢、およびEmployee_Idのプライベートフィールドを持つという名前のクラスを考えてみましょう。クラスの外部からこれらのフィールドにアクセスすることはできませんが、プロパティを通じてこれらのプライベートフィールドにアクセスすることはできます。

なぜプロパティを使用するのですか?

クラスフィールドを公開して公開するのは危険です。割り当てられて返されるものを制御できないためです。

例でこれを明確に理解するために、ID、パスマーク、名前を持つ学生のクラスを例にとってみましょう。この例では、パブリックフィールドに関するいくつかの問題

  • IDは-veであってはなりません。
  • 名前をnullに設定することはできません
  • パスマークは読み取り専用です。
  • 学生の名前が欠落している場合、名前は返されません。

この問題を取り除くにはGetメソッドとsetメソッドを使用します。

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

次に、getおよびsetメソッドの例を取り上げます。

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}

2

追加情報:デフォルトでは、getおよびsetアクセサーは、プロパティ自体と同じようにアクセスできます。より制限されたアクセス修飾子を適用することにより、(getおよびsetのために)個別にアクセサーのアクセシビリティを制御/制限できます。

例:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

ここではgetはまだパブリックにアクセスされていますが(プロパティはpublicであるため)、setは保護されています(より制限されたアクセス指定子)。


2

プロパティはフィールドを公開するために使用されます。これらは、プライベートフィールドの値を読み取り、書き込み、または操作できるアクセサ(set、get)を使用します。

プロパティは、保存場所を指定しません。代わりに、値を読み取り、書き込み、または計算するアクセサーがあります。

プロパティを使用して、フィールドに設定されているデータのタイプに検証を設定できます。

たとえば、私たちにはプライベート整数フィールドの年齢があり、年齢は負にできないため、正の値を許可する必要があります。

ゲッターとセッターを使用する方法と、プロパティを使用する方法の2つがあります。

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

自動実装プロパティ取得および設定アクセサにロジックがない場合は、自動実装プロパティを使用できます。

uがすると、自動実装プロパティのコンパイルをSEプライベート、匿名フィールド作成のみ取得し、セットアクセサーを介してアクセスすることができます。

public int Age{get;set;}

抽象プロパティ 抽象クラスには、派生クラスに実装する必要がある抽象プロパティがある場合があります。

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

プロパティをプライベートに設定できますこれで、autoプロパティをプライベートに設定できます(クラスで設定)

public int MyProperty
{
    get; private set;
}

このコードで同じことを達成できます。このプロパティでは、フィールドに値を直接設定する必要があるため、セット機能は使用できません。

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

2

ほとんどの場合、これは変数名(フィールド)ではなく、アクセスするプロパティ名になります。)では。その理由は、.NETおよびC#では特にクラス内のすべてのデータを保護する、クラスに関連付けられているため、インスタンス変数でも静的変数(クラス変数)でもかまいません。

アクセサの定義、設定、取得 を可能にする対応するプロパティでこれらの変数をすべて保護しますそれらのデータを操作するときに検証などを行うことができます。

しかし、Mathクラス(システム名前空間)などの他のケースでは、クラスに組み込まれている静的プロパティがいくつかあります。その1つは数学定数PIです。

例えば。Math.PI

また、PIは明確に定義されたデータであるため、PIの複数のコピーを用意する必要はなく、常に同じ値になります。したがって、静的変数は、クラスのオブジェクト間でデータを共有するために使用されることもありますが、データのコピーを1つだけ必要とする定数情報にも一般的に使用されます。

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