c# - 用法 - フィールドとプロパティの違いは何ですか?




get set:} (20)

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


差異 - いつ(いつ、なぜ)

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

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


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


Wikipediaより - オブジェクト指向プログラミング

オブジェクト指向プログラミング(OOP)は、「オブジェクト」の概念に基づいたプログラミングのパラダイムです。オブジェクトの概念は、 データをフィールドの形式で格納するデータ構造です。 プロシージャの形で、しばしばメソッドとして知られています(強調が加えられた)

プロパティは実際にはオブジェクトのビヘイビアの一部ですが、オブジェクトのコンシューマにオブジェクトのデータを扱う錯覚/抽象を与えるように設計されています。


(これは本当にコメントでなければなりませんが、コメントを投稿できませんので、投稿としては適切でない場合は申し訳ありません)。

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

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

彼らの推論は、必要に応じて将来公共のフィールドを後に財産に変換できるということでした。 当時私は少し奇妙に思えました。 これらの記事で判断すると、ここではあまり好きではないようです。 物事を変えようとしたことは何ですか?

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


ここでの2番目の質問は、「いつ財産の代わりにフィールドを使うべきか」ということですが、 この他の回答では簡単に触れられています。

一般的に、他のすべての答えは、良いデザインについてスポットを当てています。 おそらくあなたはたぶん自分自身を見つけることはありませんが、「うわー、私はこれを財産ではなくフィールドにしたらもっと悪いことを想像してください」と言っている状況を考えるのはずっと稀です。私は財産の代わりにここに畑を使用しました。

しかし、フィールドがプロパティよりも優れているという利点があり、それは "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);
}

いくつかのmeasurements自分で行うと、フィールドを持つバージョンでは、プロパティのバージョン(.NET 4.6、Windows 7、x64、リリースモード、デバッガが接続されていない)として約61%の時間がかかります。 TransformPointメソッドがより高価になればなるほど、その差異が顕著になります。 これを繰り返すには、最初の行をコメントアウトしてコメントアウトして実行します。

上記のパフォーマンス上の利点がない場合でも、 InterlockedまたはVolatileのメソッドファミリを呼び出すときなど、refおよびoutパラメータを使用できることが有益な場合があります。 注:これはあなたに初めての場合、揮発性は基本的にはvolatileキーワードによって提供される同じ動作を取得する方法です。 したがって、 volatileように、その名前のようにすべてのスレッドセーフな苦境を魔法のように解決するわけではありません。

私は間違いなくあなたが "ああ、私はプロパティの代わりにフィールドを公開する必要があります"と主張しているように思われたくありません。 要点は、 "ref"または "out"パラメータを取る呼び出し、特にプロパティの付加価値要素を必要としない単純な値型である可能性のある呼び出しでこれらのメンバーを定期的に使用する必要がある場合、議論ができます。


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

したがって、値がxより大きい場合にのみ整数フィールドに値を設定したい場合は、例外をスローします。

本当に便利な機能。


ギアを回転させる可能性のあるプロパティを使用する例をいくつか挙げておきます。

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

スレッドプリミティブを使用する場合は、フィールドを使用する必要があります。 プロパティはスレッドコードを壊すことがあります。 それ以外は、どんなコーリーが正しいと言いましたか?


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

  class SomeClass
  {
     int numbera; //Field

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

  }

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

たとえば、 "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";
    }
}

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

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

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

クラスフィールドを公開して公開するのは危険です。割り当てられて返されるものを制御することはできません。

この例を明確に理解するには、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つのうちの一方だけを持つことができます。 同様に、プロパティはゲッタ/セッタの個々のアクセシビリティをサポートします。 フィールドは常に対称です。つまり、値を取得したり設定したりすることができます。 例外として、初期化後には明示的には設定できない読み取り専用フィールドがあります。

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

フィールドはout / refパラメータに使用できますが、プロパティは使用できません。 プロパティは追加のロジックをサポートします - これは他のものの間で遅延ロードを実装するために使用できます。

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

大部分/すべての場合にプロパティを使用しますが、副作用は避けてください。


プロパティを使用すると、プロパティの値が変更されたとき(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(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}

多くの人がPropertiesField技術的賛否両論を説明してきたので、リアルタイムの例に入るときが来ました。

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

dataTable.Rows.CountdataTable.Columns[i].Captionの場合を考えてみましょう。 彼らはクラスDataTableから来て、両方が私たちに公開されています。 それらのアクセスレベルの違いは、 dataTable.Rows.Count値を設定できないことdataTable.Rows.Countが、 dataTable.Columns[i].Caption読み書きできます。 それはFieldを通して可能ですか? いいえ! これは、 Propertiesのみ実行でき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のプロパティ

あなたは、Visual StudioでButtonしたかもしれません。 そのプロパティは、 TextNameなどのPropertyGrid表示されます。ボタンをドラッグアンドドロップすると、プロパティをクリックすると自動的にクラスButton検索され、 Propertiesフィルタされ、 PropertyGrid表示されPropertiesPropertyGridは表示されません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表示されませSomeProperty 。 なぜ??? プロパティはAttributesを受け入れることができるためです。 [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. Binding Sourceでプロパティのみを使用できます。

Binding Sourceは、コード行数を減らすのに役立ちます。 FieldsBindingSourceによって受け入れられません。 そのためにPropertiesを使用する必要がありProperties

5.デバッグモード

Fieldを使用して値を保持しているとします。 ある時点で、そのフィールドの値がどこでヌルになっているのかをデバッグして調べる必要があります。 このような状況では、 Propertyを使用することができ、 Property内でデバッグモードを設定することができます。

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

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


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


それについて考える:この部屋に入るには部屋と扉がある。誰が来ているかを確認して部屋を確保したい場合は、プロパティを使用する必要があります。それ以外の場合はドアが開かず、誰でも簡単にすべての規制が適用されます

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";

今あなたはその人をチェックし、彼が彼と何か悪いことをしているかどうかを知っている


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

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

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

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

getterとsetterを使用し、プロパティを使用する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;
     }
  }

私たちは個人的にプロパティを設定することができますこれで私たちは自動的にプロパティを設定することができます(クラスで設定)

public int MyProperty
{
    get; private set;
}

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

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

大多数のケースでは、変数名(フィールド)とは対照的に、アクセスするプロパティ名になります。その理由は、.NETとC#では、特にクラス内のすべてのデータを保護するための良い方法ですクラスに関連付けられているため、インスタンス変数か静的変数(クラス変数)のどちらであろうと、

これらの変数をすべて対応するプロパティで保護します。これらのプロパティを使用すると、 accessorsを定義、設定、取得することができ、これらのデータを操作するときに検証のようなことを実行できます。

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

例えば。 数学

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





field