web-dev-qa-db-ja.com

C#でプライベートプロパティを使用する理由はありますか?

私は、C#property constructprivateアクセス修飾子とともに使用できることを認識しました:

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つですか?

補遺

素敵な答え、それらを読んで私は私有財産のこれらの使用をしました:

  • プライベートフィールドを遅延ロードする必要がある場合
  • プライベートフィールドに追加のロジックが必要な場合、または計算値である場合
  • プライベートフィールドはデバッグが難しい可能性があるため
  • 「自分に契約を提示する」ため
  • シリアル化の一部として公開されたプロパティを内部的に変換/単純化する
  • クラス内で使用されるグローバル変数のラッピング
216
Edward Tanguay

値をキャッシュし、遅延ロードしたい場合に使用します。

private string _password;
private string Password
{
    get
    {
        if (_password == null)
        {
            _password = CallExpensiveOperation();
        }

        return _password;
    }
}
191
Shaun Bowe

私のコードでこれを主に使用するのは、他の人が述べたように、遅延初期化です。

フィールドに対するプライベートプロパティのもう1つの理由は、プライベートプロパティがプライベートフィールドよりもはるかに簡単にデバッグできることです。 「このフィールドが予期せず設定されています。このフィールドを設定する最初の呼び出し元は誰ですか?」などのことを頻繁に知りたいです。セッターにブレークポイントを設定してgoキーを押すだけで簡単に実行できます。そこにログインすることができます。そこにパフォーマンスメトリックを配置できます。デバッグビルドで実行される整合性チェックを行うことができます。

基本的には、コードはデータよりもはるかに強力ですです。必要なコードを記述できる手法はどれも優れています。フィールドではコードを記述できませんが、プロパティではできます。

124
Eric Lippert

ネストされた/継承されたクラスのユースケースがあるか、プロパティの値を返すだけではなく、get/setにロジックが含まれる場合があります

プロパティのゲッターまたはセッターのロジックが必要ない場合でも、私は個人的にこれを使用します。プライベートプロパティであっても、プロパティを使用することでコードを将来にわたって保証し、必要に応じて後でゲッターにロジックを追加できます。

プロパティが最終的に追加のロジックを必要とする可能性があると感じた場合、フィールドを使用する代わりにプライベートプロパティにラップすることがあります。これにより、後でコードを変更する必要がなくなります。


半関連の場合(質問とは異なりますが)、私は非常に頻繁にパブリックプロパティでプライベートセッターを使用します。

public string Password 
{
    get; 
    private set;
}

これにより、パブリックgetterが提供されますが、setterはプライベートになります。

40
Reed Copsey

遅延初期化は、きれいにできる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#がプロパティへのバッキングフィールドのスコープ(つまり、プロパティ定義内での宣言)をサポートしていないことです。

20
Greg Beech

プライベート取得専用プロパティの適切な使用方法の1つは、計算値です。プライベート読み取り専用のプロパティがあり、自分のタイプの他のフィールドに対して計算を行うだけです。メソッドに値するものではなく、他のクラスにとっても興味深いものではないため、プライベートプロパティです。

18
JaredPar

私が考えることができる唯一の使用法

private bool IsPasswordSet 
{ 
     get
     {
       return !String.IsNullOrEmpty(_password);
     }
}
12
Lukasz Madon

プロパティとフィールドは一対一ではありません。プロパティはクラスのインターフェイスに関するものであり(パブリックインターフェイスまたは内部インターフェイスについて)、フィールドはクラスの実装に関するものです。プロパティは、フィールドを単に公開する方法と見なされるべきではなく、クラスの意図と目的を公開する方法と見なされるべきです。

プロパティを使用して、クラスを構成するものについて契約を消費者に提示するのと同じように、非常に類似した理由で自分自身に契約を提示することもできます。そう、私はそれが理にかなっているときにプライベートプロパティを使用します。プライベートプロパティは、遅延読み込み、プロパティが実際に複数のフィールドとアスペクトの集合体である、または各呼び出しでプロパティを仮想的にインスタンス化する必要があるなど、実装の詳細を隠すことができます(DateTime.Nowと考えてください)。クラスのバックエンドで自分自身にもこれを強制することが理にかなっている場合があります。

10
Matt Greer

この使用をサポートするDataContractSerializerやprotobuf-netのようなもので、シリアル化で使用します(XmlSerializerはサポートしません)。シリアル化の一部としてオブジェクトを簡素化する必要がある場合に便利です。

public SomeComplexType SomeProp { get;set;}
[DataMember(Order=1)]
private int SomePropProxy {
    get { return SomeProp.ToInt32(); }
    set { SomeProp = SomeComplexType.FromInt32(value); }
}
8
Marc Gravell

私がいつもやっていることの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;
  }
}
6
Earlz

プライベートプロパティを使用して、頻繁に使用するサブプロパティにアクセスするためのコードを削減します。

    private double MonitorResolution
    {
        get { return this.Computer.Accesories.Monitor.Settings.Resolution; }
    }

多くのサブプロパティがある場合に便利です。

5

私は時々それらを使用します。プロパティにブレークポイントを簡単に配置できる場合や、ロギングステートメントなどを追加できる場合は、デバッグが容易になります。

後で何らかの方法でデータのタイプを変更する必要がある場合、またはリフレクションを使用する必要がある場合にも役立ちます。

5
Hans Olsson

プライベートメソッドを含むget/setメソッドでのみメンバーを変更するのが一般的です。さて、この背後にあるロジックは、get/setが常に特定の方法で動作することを知っているためです(たとえば、イベントを起動する)。これらはプロパティスキームに含まれないため、意味をなさないようです。しかし、古い習慣は激しく死にます。

2
corsiKa

プロパティの設定または取得に関連するロジックがあり(レイジー初期化を考えてください)、プロパティがクラス内のいくつかの場所で使用されている場合、これは完全に理にかなっています。

単なる裏打ちフィールドの場合は?正当な理由として何も思い浮かぶことはありません。

2
Marc

私はこの質問が非常に古いことを知っていますが、以下の情報は現在の回答のいずれにもありませんでした。

内部で取得できるが設定されないようにする必要がいつになるか想像できない

依存関係を注入する場合は、読み取り専用プロパティを示すため、セッターではなくプロパティにゲッターを設定することをお勧めします。つまり、プロパティはコンストラクターでのみ設定でき、クラス内の他のコードによって変更することはできません。

また、Visual Studio Professionalは、フィールドではなくプロパティに関する情報を提供し、フィールドが使用されていることを簡単に確認できるようにします。

PorpField

1
Guy

さて、誰も言及していないように、それを使用してデータを検証したり、変数をロックしたりできます。

  • 検証

    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に変更すると名前が変更され、シリアライザが破損します)
0
Marc Gravell