C# では、フィールドとプロパティの違いは何ですか? また、プロパティの代わりにフィールドを使用する必要があるのはどのような場合ですか?
33 に答える
プロパティはフィールドを公開します。フィールドは (ほとんどの場合) クラスに対してプライベートに保ち、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 は、プロパティがアクセスされたときに、検証などの他のロジックも実行できることを指摘しています。これは、もう 1 つの便利な機能です。
オブジェクト指向プログラミングの原則では、クラスの内部動作は外部の世界から隠されている必要があります。フィールドを公開すると、本質的にクラスの内部実装が公開されます。したがって、フィールドをプロパティ (または 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
}
重要な違いは、インターフェースはプロパティを持つことができますが、フィールドを持つことはできないということです。これは、私にとって、プロパティはクラスのパブリックインターフェイスを定義するために使用されるべきであり、フィールドはクラスのプライベートな内部動作で使用されることを意図していることを強調しています。原則として、パブリックフィールドを作成することはめったになく、同様に非パブリックプロパティを作成することもめったにありません。
ギアを回すプロパティの使用例をいくつか紹介します。
- Lazy Initialization :読み込みにコストがかかるが、コードの通常の実行ではあまりアクセスされないオブジェクトのプロパティがある場合は、プロパティを介して読み込みを遅らせることができます。そのようにして、そこに座っているだけですが、別のモジュールがそのプロパティを初めて呼び出そうとすると、基礎となるフィールドが null かどうかをチェックします。これにより、オブジェクトの初期化を大幅に高速化できます。
- ダーティ トラッキング: StackOverflow に関する自分の質問から実際に学んだことです。実行中に値が変更された可能性のあるオブジェクトが多数ある場合、プロパティを使用して、それらをデータベースに保存する必要があるかどうかを追跡できます。オブジェクトの単一のプロパティが変更されていない場合、IsDirty フラグはトリップされないため、データベースに戻す必要があるものを決定する際に、保存機能はそれをスキップします。
プロパティを使用すると、プロパティの値が変更されたとき (別名、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);
}
}
それらの多くは と の技術的な長所と短所を説明しているので、Properties
リアルタイムField
の例に入る時が来ました。
1. プロパティでは、読み取り専用アクセス レベルを設定できます
と の場合を考えてみましょdataTable.Rows.Count
うdataTable.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 のプロパティ
Button
Visual Studio で作業したことがあるかもしれません。ボタンをドラッグ アンド ドロップし、プロパティをクリックすると、自動的にクラスとフィルターが検索されて表示されPropertyGrid
ます(パブリックであっても表示されない場所)。Text
Name
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
、プロパティName
とText
は表示されますが、 は表示されませんSomeProperty
。どうして???Properties はAttributesを受け入れることができるためです。[Browsable(false)]
whereが 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;
}
}
違い - 用途 (いつ、なぜ)
フィールドは、クラスまたは構造体で直接宣言される変数です。クラスまたは構造体は、インスタンス フィールドまたは静的フィールド、あるいはその両方を持つことができます。一般に、プライベートまたは保護されたアクセシビリティを持つ変数にのみフィールドを使用する必要があります。クラスがクライアント コードに公開するデータは、メソッド、プロパティ、およびインデクサーを通じて提供する必要があります。内部フィールドへの間接アクセスにこれらの構成を使用することで、無効な入力値を防ぐことができます。
プロパティは、プライベート フィールドの値を読み取り、書き込み、または計算するための柔軟なメカニズムを提供するメンバーです。プロパティは、パブリック データ メンバーであるかのように使用できますが、実際にはアクセサーと呼ばれる特別なメソッドです。これにより、データへのアクセスが容易になり、メソッドの安全性と柔軟性が向上します。プロパティを使用すると、実装または検証コードを隠しながら、値を取得および設定するパブリックな方法をクラスで公開できます。get プロパティ アクセサーはプロパティ値を返すために使用され、set アクセサーは新しい値を割り当てるために使用されます。
プロパティには、パブリック インターフェイスを壊すことなく、オブジェクトのデータにアクセスする方法を変更できるという主な利点があります。たとえば、追加の検証を追加する必要がある場合、または保存されたフィールドを計算されたフィールドに変更する必要がある場合、最初にフィールドをプロパティとして公開していれば、簡単に行うことができます。フィールドを直接公開しただけの場合は、クラスのパブリック インターフェイスを変更して新しい機能を追加する必要があります。この変更は既存のクライアントを壊し、新しいバージョンのコードを使用する前に再コンパイルする必要があります。
(何百万人もの人々によって使用されている .NET Framework のように) 広く使用されるように設計されたクラス ライブラリを作成すると、問題が発生する可能性があります。ただし、小さなコード ベース (たとえば <= 50 K 行) 内で内部的に使用されるクラスを作成している場合は、変更によって誰も悪影響を受けないため、実際には大したことではありません。その場合、それは本当に個人的な好みに帰着します。
プロパティは非対称アクセスをサポートしています。つまり、getter と setter のいずれか、または 2 つのうちの 1 つだけを持つことができます。同様に、プロパティは getter/setter の個別のアクセシビリティをサポートします。フィールドは常に対称です。つまり、常に値を取得および設定できます。これに対する例外は、明らかに初期化後に設定できない読み取り専用フィールドです。
プロパティは非常に長時間実行され、副作用があり、例外がスローされることさえあります。フィールドは高速で、副作用がなく、例外がスローされることはありません。副作用のため、プロパティは呼び出しごとに異なる値を返す場合があります (DateTime.Now の場合と同様に、DateTime.Now は常に DateTime.Now と等しいとは限りません)。フィールドは常に同じ値を返します。
フィールドは out / ref パラメータに使用できますが、プロパティは使用できません。プロパティは追加のロジックをサポートします。これは、特に遅延読み込みを実装するために使用できます。
プロパティは、値を取得/設定することを意味するものをカプセル化することにより、抽象化のレベルをサポートします。
ほとんど/すべての場合にプロパティを使用しますが、副作用を避けるようにしてください。
バックグラウンドでは、プロパティがメソッドにコンパイルされます。したがって、Name
プロパティはとにコンパイルされget_Name()
ますset_Name(string value)
。コンパイルされたコードを調べると、これを確認できます。したがって、それらを使用する場合、(非常に)小さなパフォーマンスオーバーヘッドがあります。通常、フィールドを外部に公開する場合は常にプロパティを使用し、値の検証を行う必要がある場合は内部で使用することがよくあります。
また、プロパティを使用すると、値を設定するときにロジックを使用できます。
したがって、値がxより大きい場合は整数フィールドにのみ値を設定したいと言うことができ、そうでない場合は例外をスローします。
本当に便利な機能。
フィールドは、クラスの通常のメンバー変数またはメンバー インスタンスです。プロパティは、その値を取得および設定するための抽象化です。プロパティは、クラス内のフィールドをプライベートとして公開する場合にフィールドを変更および取得する方法を提供するため、アクセサーとも呼ばれます。一般に、メンバー変数をプライベートに宣言してから、それらのプロパティを宣言または定義する必要があります。
class SomeClass
{
int numbera; //Field
//Property
public static int numbera { get; set;}
}
プロパティは、ユーザーによって作成されたフィールドまたはコンパイラによって自動的に作成されたフィールドの単なるラッパーであるため、技術的には違いがあるとは思いません。プロパティの目的は、カプセル化を強制し、軽量のメソッドのような機能を提供することです。フィールドをパブリックとして宣言するのは悪い習慣ですが、問題はありません。
スレッド プリミティブを使用する場合は、フィールドを使用する必要があります。プロパティは、スレッド化されたコードを壊す可能性があります。それを除けば、コリーの言ったことは正しい。
基本的な違いと一般的な違いは次のとおりです。
田畑
- 常にget アクセスと set アクセスの両方を与える
- 副作用を引き起こすことはできません(例外のスロー、メソッドの呼び出し、取得/設定されているフィールド以外のフィールドの変更など)
プロパティ
- 常にget アクセスと set アクセスの両方を与えるわけではありません
- 副作用を引き起こす可能性があります
(本当はコメントのはずなのですが、コメントを投稿できないので、投稿としてふさわしくない場合はご容赦ください)。
私はかつて、次のように、同等のプロパティ定義がフィールドにアクセスしているだけの場合に、プロパティの代わりにパブリックフィールドを使用することが推奨される場所で働いていました。
get { return _afield; }
set { _afield = value; }
彼らの理由は、必要に応じて public フィールドを後でプロパティに変換できるというものでした。当時の私には少し奇妙に思えました。これらの投稿から判断すると、ここでも同意する人はあまりいないようです. 物事を変えようとするために何を言ったでしょうか?
編集:この場所のすべてのコードベースが同時にコンパイルされたことを追加する必要があるため、クラスのパブリックインターフェイスを変更すること(パブリックフィールドをプロパティに変更することによって)は問題ではないと考えた可能性があります。
プロパティはフィールドをカプセル化するため、設定または取得する値に対して追加の処理を実行できます。フィールド値に対して前処理または後処理を行わない場合、通常、プロパティを使用するのはやり過ぎです。
「車」のクラスがある場合。プロパティは、色、形状..
フィールドは、クラスのスコープ内で定義された変数です。
ウィキペディアから --オブジェクト指向プログラミング:
オブジェクト指向プログラミング (OOP) は、「オブジェクト」の概念に基づいたプログラミング パラダイムです。オブジェクトは、属性として知られるフィールドの形式でデータを含むデータ構造です。コードは、プロシージャの形式で、メソッドとして知られています。(強調追加)
プロパティは、実際にはオブジェクトの動作の一部ですが、オブジェクトのデータを操作しているという錯覚/抽象化をオブジェクトの消費者に与えるように設計されています。
従来、private フィールドは getter メソッドと setter メソッドを介して設定されていました。コードを減らすために、代わりにプロパティを使用してフィールドを設定できます。
追加情報: デフォルトでは、get アクセサーと set アクセサーはプロパティ自体と同じようにアクセスできます。より制限的なアクセス修飾子を適用することで、アクセサーのアクセシビリティを (get および set に対して) 個別に制御/制限できます。
例:
public string Name
{
get
{
return name;
}
protected set
{
name = value;
}
}
ここで、get はパブリックにアクセスされますが (プロパティが public であるため)、set は保護されています (より制限されたアクセス指定子)。
プロパティは特別な種類のクラス メンバーです。プロパティでは、事前定義された Set または Get メソッドを使用します。それらは、プライベート フィールドの値を読み取り、書き込み、または変更できるアクセサーを使用します。
たとえば、Employee
name、age、Employee_Id のプライベート フィールドを持つ という名前のクラスを考えてみましょう。クラスの外部からこれらのフィールドにアクセスすることはできませんが、プロパティを通じてこれらのプライベート フィールドにアクセスできます。
プロパティを使用する理由
クラスフィールドを公開して公開することは、何が割り当てられて返されるかを制御できないため、危険です。
例でこれを明確に理解するために、ID、パスマーク、名前を持つ学生クラスを見てみましょう。この例では、 public フィールドに問題があります
- 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;
}
}