web-dev-qa-db-ja.com

プライベート変数vsプロパティ?

クラス内の変数に値を設定する場合、ほとんどの場合、2つのオプションが提示されます。

private string myValue;
public string MyValue
{
   get { return myValue; }
   set { myValue = value; }
}

クラス内の変数に値を割り当てる方法を決定する規則はありますか?たとえば、同じクラス内にメソッドがある場合、プロパティまたはプライベート変数を使用して割り当てる必要があります。私はそれが両方の方法で行われるのを見たので、これが選択であるのか、それともパフォーマンスが要因であるのか(おそらくマイナーなのか)疑問に思っていました。

42
Edward

私はそれをさらに一歩進めて、3つのケースに持ち込みます。それぞれにバリエーションがありますが、これはC#プログラミングで大部分の場合に使用するルールです。

ケース2と3の場合は、(フィールド変数ではなく)常にプロパティアクセサーに移動します。そしてケース1では、この選択をしなくても済むようになります。

1.)不変のプロパティ(コンストラクターに渡されるか、構築時に作成されます)。この場合は、読み取り専用プロパティを持つフィールド変数を使用します。プライベートセッターは不変性を保証しないため、私はプライベートセッターよりもこれを選択します。

public class Abc
{ 
  private readonly int foo;

  public Abc(int fooToUse){
    foo = fooToUse;
  }

  public int Foo { get{ return foo; } }
}

2.)POCO変数。任意のパブリック/プライベートスコープで取得/設定できる単純な変数。この場合、自動プロパティを使用します。

public class Abc
{ 
  public int Foo {get; set;}
}

3.)ViewModelバインディングプロパティ。 INotifyPropertyChangedをサポートするクラスの場合、プライベートなバッキングフィールド変数が必要だと思います。

public class Abc : INotifyPropertyChanged
{
  private int foo;

  public int Foo
  {
    get { return foo; }
    set { foo = value;  OnPropertyChanged("foo"); }
  }
}
24

一般に、コンストラクターのフィールドに割り当てて、プロパティを他の場所で使用します。このようにして、誰かがプロパティに機能を追加しても、どこかで見逃すことはありません。

それは確かにパフォーマンスの要因ではありません。オプティマイザは単純なgetまたはsetをインライン化し、最終的なMSILコードはおそらく同じになります。

18
pdr

依存します。

最初に、可能な場合は自動プロパティを優先する必要があります。

public string MyValue {get;set;}

次に、プロパティを使用するのがおそらくより良い方法です。ロジックがある場合は、自分でパススルーする必要があります。特に、そのロジックがスレッド同期の場合はそうです。

ただし、パフォーマンスを低下させる可能性があることも考慮する必要があります(少しだけ)。誤って同期している場合は、自分でデッドロックする可能性があります。また、正しいパスは、プロパティのロジックを回避することです。

4
AK_

まあ、直接的なアプローチは、変数自体に割り当てるだけです。クラスのメソッドの内部にいて、とにかくクラスの動作を制御しているからです。

しかし、プロパティに関する全体的なポイントは、それらが変数を抽象化することです。例のような単純なプロパティは単純なパブリックメンバー変数だけではまったく役に立たないのに対し、プロパティは通常、ゲッターとセッターの内部で追加の機能を実行します(または実行する必要があります)。また、クラス内のプロパティを変更するときにこれらのことを自動的に実行したい場合は、プロパティ設定の動作が変更されたときに各変数の割り当てを変更する必要がないように、変数の代わりにプロパティを操作する方が無難です。

概念的にそれについて推論する必要があります。プロパティは、実際にはオブジェクトの内部状態にアクセスするためのハンドルであり、複数のメンバー変数で構成されている場合があります。したがって、基礎となる内部状態のみ(またはその一部のみ)を変更するか、この状態を全体的に表す抽象プロパティを変更するかを自問する必要があります。たいていの場合、オブジェクトには常に一貫した状態。

これらのプロパティのget/set実装が後で変更される可能性がある場合(たとえば、setを呼び出すときにイベントを発生させたい場合や、後で遅延評価メカニズムをget function)、次に、クラス内のコードが、ほとんどの場合を除いて、ほとんどの場合にプロパティを使用することをお勧めします-おそらく-明示的にしないでください使用するイベントまたは遅延評価メカニズム。

とにかく、あなたが何をするにしても、そのような方法でプロパティの実装を後で変更するとき、それらのプロパティにアクセスするクラス内のすべての場所を調べて、実際にプロパティがアクセスされるかどうかを確認する必要があるか、プライベート変数が使用されます。

2
Doc Brown

私は常にパブリックプロパティを使用します。

多くの場合、プロパティの設定時に常に実行する必要があるロジックがプロパティのsetメソッドに追加され、代わりにプライベートセッターを設定すると、パブリックセッターがそのロジックをバイパスします。

この質問につながるMVVMについてのコメントがありますが、MVVMを操作する場合、これはさらに重要だと思います。多くのオブジェクトはPropertyChange通知セッターを発生させ、他のオブジェクトはこのイベントをサブスクライブして、特定のプロパティが変更されたときにアクションを実行できます。プライベート変数を設定した場合、PropertyChangedイベントを手動で発生させない限り、これらのアクションは実行されません。

2
Rachel

一般に、取得/設定時にプロパティとそのバッキングフィールドをどうするかは、あなた次第です。

ほとんどの場合、コード全体で一貫性を保つために、パブリックアクセサーが利用可能で適切な場所であればどこでも使用する必要があります。これにより、最小限のコード変更でリファクタリングできます。この設定を行うメソッドをクラスから削除し、バッキングフィールドが利用できない場所(基本クラスなど)のどこかに置く必要がある場合、誰が気にしますか?クラス自体が仕事をするために利用できるものを使用しています。バッキングフィールドは、ほとんどの場合、実装の詳細です。あなたのクラスの外の誰もそれが存在することを知らないはずです。

プロパティアクセサーではなくバッキングフィールドを使用する必要がある主な状況は、実行したくない追加のロジック(検証、またはクラス内の他の状態情報の更新)がある場合です。オブジェクトの初期母集団は一例です。 2つのプロパティ値を使用して3つ目の値を計算するクラスがあり、これもバッキングフィールドに保存されます(永続性の理由から)。 DBからのデータを指定してそのオブジェクトの新しいコピーを初期化するときに、3番目の値をそれぞれ再計算するプロパティアクセサーは、他の必要な値が設定されていない場合、文句を言うことがあります。バッキングフィールドを使用してこれら2つ(または3つ)のプロパティの初期値を設定することで、ロジックが正常に機能するのに十分な一貫性のある状態になるまで、検証/計算ロジックをバイパスします。

1
KeithS

常に意味のあるものを使用してください。はい、私はそれが無回答であるという点でかなり偽物に聞こえることを知っています。

プロパティのポイントは、データモデルに安全にアクセスできるインターフェイスを提供することです。ほとんどの場合、次のように、そのインターフェースを介してデータモデルに常に安全にアクセスする必要があります。

public Foo Bar
{
  get { return _bar; }
  set { _bar = doSomethingTo(value); }
}

しかし、他の状況では、単にデータモデルのビューとしてプロパティを使用している可能性があります。

public Double SomeAngleDegrees
{
  get { return SomeAngleRadians * 180 / PI; }
  set { SomeAngleRadians = value * PI / 180; }
}

SomeAngleのラジアン形式を使用することが理にかなっている場合は、必ずそれを使用してください。

最後に、必ず自分のエイドを飲んでください。公開用のAPIは、内部で動作するのに十分な復元力を備えている必要があります。

0
zzzzBov