私は、C#property constructがprivateアクセス修飾子とともに使用できることを認識しました:
private string Password { get; set; }
これは技術的に興味深いものですが、private fieldにはless式さえ含まれるため、いつ使用するか想像できません:
private string _password;
そして、私は内部的にできるようになる必要があると想像することはできませんgetしかし setまたはsetbut notgetプライベートフィールド:
private string Password { get; }
または
private string Password { set; }
しかし、おそらくネストされた/継承されたクラスのユースケースがあるか、またはプロパティの値を返すだけでなく、get/setにlogicが含まれる場合がありますプロパティを厳密にシンプルに保ち、明示的なメソッドにロジックを実行させる傾向があります。例えばGetEncodedPassword()
。
何らかの理由でC#でプライベートプロパティを使用する人はいますか、それとも技術的に可能だが実際に使用される実際のコード構造の1つですか?
素敵な答え、それらを読んで私は私有財産のこれらの使用をしました:
値をキャッシュし、遅延ロードしたい場合に使用します。
private string _password;
private string Password
{
get
{
if (_password == null)
{
_password = CallExpensiveOperation();
}
return _password;
}
}
私のコードでこれを主に使用するのは、他の人が述べたように、遅延初期化です。
フィールドに対するプライベートプロパティのもう1つの理由は、プライベートプロパティがプライベートフィールドよりもはるかに簡単にデバッグできることです。 「このフィールドが予期せず設定されています。このフィールドを設定する最初の呼び出し元は誰ですか?」などのことを頻繁に知りたいです。セッターにブレークポイントを設定してgoキーを押すだけで簡単に実行できます。そこにログインすることができます。そこにパフォーマンスメトリックを配置できます。デバッグビルドで実行される整合性チェックを行うことができます。
基本的には、コードはデータよりもはるかに強力ですです。必要なコードを記述できる手法はどれも優れています。フィールドではコードを記述できませんが、プロパティではできます。
ネストされた/継承されたクラスのユースケースがあるか、プロパティの値を返すだけではなく、get/setにロジックが含まれる場合があります
プロパティのゲッターまたはセッターのロジックが必要ない場合でも、私は個人的にこれを使用します。プライベートプロパティであっても、プロパティを使用することでコードを将来にわたって保証し、必要に応じて後でゲッターにロジックを追加できます。
プロパティが最終的に追加のロジックを必要とする可能性があると感じた場合、フィールドを使用する代わりにプライベートプロパティにラップすることがあります。これにより、後でコードを変更する必要がなくなります。
半関連の場合(質問とは異なりますが)、私は非常に頻繁にパブリックプロパティでプライベートセッターを使用します。
public string Password
{
get;
private set;
}
これにより、パブリックgetterが提供されますが、setterはプライベートになります。
遅延初期化は、きれいにできる1つの場所です。
private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */);
private MyType MyType { get { return this.mytype.Value; } }
// In C#6, you replace the last line with: private MyType MyType => myType.Value;
その後、次のように書くことができます:this.MyType
ではなくthis.mytype.Value
どこでも、単一の場所で遅延的にインスタンス化されるという事実をカプセル化します。
残念なことの1つは、C#がプロパティへのバッキングフィールドのスコープ(つまり、プロパティ定義内での宣言)をサポートしていないことです。
プライベート取得専用プロパティの適切な使用方法の1つは、計算値です。プライベート読み取り専用のプロパティがあり、自分のタイプの他のフィールドに対して計算を行うだけです。メソッドに値するものではなく、他のクラスにとっても興味深いものではないため、プライベートプロパティです。
私が考えることができる唯一の使用法
private bool IsPasswordSet
{
get
{
return !String.IsNullOrEmpty(_password);
}
}
プロパティとフィールドは一対一ではありません。プロパティはクラスのインターフェイスに関するものであり(パブリックインターフェイスまたは内部インターフェイスについて)、フィールドはクラスの実装に関するものです。プロパティは、フィールドを単に公開する方法と見なされるべきではなく、クラスの意図と目的を公開する方法と見なされるべきです。
プロパティを使用して、クラスを構成するものについて契約を消費者に提示するのと同じように、非常に類似した理由で自分自身に契約を提示することもできます。そう、私はそれが理にかなっているときにプライベートプロパティを使用します。プライベートプロパティは、遅延読み込み、プロパティが実際に複数のフィールドとアスペクトの集合体である、または各呼び出しでプロパティを仮想的にインスタンス化する必要があるなど、実装の詳細を隠すことができます(DateTime.Now
と考えてください)。クラスのバックエンドで自分自身にもこれを強制することが理にかなっている場合があります。
この使用をサポートするDataContractSerializer
やprotobuf-netのようなもので、シリアル化で使用します(XmlSerializer
はサポートしません)。シリアル化の一部としてオブジェクトを簡素化する必要がある場合に便利です。
public SomeComplexType SomeProp { get;set;}
[DataMember(Order=1)]
private int SomePropProxy {
get { return SomeProp.ToInt32(); }
set { SomeProp = SomeComplexType.FromInt32(value); }
}
私がいつもやっていることの1つは、「グローバル」変数/キャッシュをHttpContext.Current
に保存することです
private static string SomeValue{
get{
if(HttpContext.Current.Items["MyClass:SomeValue"]==null){
HttpContext.Current.Items["MyClass:SomeValue"]="";
}
return HttpContext.Current.Items["MyClass:SomeValue"];
}
set{
HttpContext.Current.Items["MyClass:SomeValue"]=value;
}
}
プライベートプロパティを使用して、頻繁に使用するサブプロパティにアクセスするためのコードを削減します。
private double MonitorResolution
{
get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
}
多くのサブプロパティがある場合に便利です。
私は時々それらを使用します。プロパティにブレークポイントを簡単に配置できる場合や、ロギングステートメントなどを追加できる場合は、デバッグが容易になります。
後で何らかの方法でデータのタイプを変更する必要がある場合、またはリフレクションを使用する必要がある場合にも役立ちます。
プライベートメソッドを含むget/setメソッドでのみメンバーを変更するのが一般的です。さて、この背後にあるロジックは、get/setが常に特定の方法で動作することを知っているためです(たとえば、イベントを起動する)。これらはプロパティスキームに含まれないため、意味をなさないようです。しかし、古い習慣は激しく死にます。
プロパティの設定または取得に関連するロジックがあり(レイジー初期化を考えてください)、プロパティがクラス内のいくつかの場所で使用されている場合、これは完全に理にかなっています。
単なる裏打ちフィールドの場合は?正当な理由として何も思い浮かぶことはありません。
さて、誰も言及していないように、それを使用してデータを検証したり、変数をロックしたりできます。
検証
string _password;
string Password
{
get { return _password; }
set
{
// Validation logic.
if (value.Length < 8)
{
throw new Exception("Password too short!");
}
_password = value;
}
}
ロック
object _lock = new object();
object _lockedReference;
object LockedReference
{
get
{
lock (_lock)
{
return _lockedReference;
}
}
set
{
lock (_lock)
{
_lockedReference = value;
}
}
}
注:参照をロックする場合、参照されるオブジェクトのメンバーへのアクセスはロックしません。
レイジーリファレンス:レイジーロードの場合、非同期 AsyncLazy が存在する非同期を実行する必要が生じる場合があります。 Visual Studio SDK 2015よりも古いバージョンを使用している場合、または使用していない場合は、 AsyncExのAsyncLazy を使用することもできます。
明示的なフィールドのよりエキゾチックな使用には、次のものがあります。
ref
またはout
を値とともに使用する必要があります-おそらくInterlocked
カウンターであるためstruct
の基本的なレイアウトを表します(おそらくC++ダンプ、またはunsafe
コードにマップします)BinaryFormatter
で自動フィールド処理で使用されてきました(auto-propsに変更すると名前が変更され、シリアライザが破損します)