これを行うC#クラスのサンプルコードがたくさんあります。
public class Point {
public int x { get; set; }
public int y { get; set; }
}
または、古いコードでは、明示的なプライベートバッキング値と同じで、新しい自動実装プロパティはありません:
public class Point {
private int _x;
private int _y;
public int x {
get { return _x; }
set { _x = value; }
}
public int y {
get { return _y; }
set { _y = value; }
}
}
私の質問はなぜですか。上記の操作を行うことと、これらのメンバーをパブリックフィールドにすることの間に、以下のような機能的な違いはありますか?
public class Point {
public int x;
public int y;
}
明確にするために、基礎となるデータの翻訳を行う必要がある場合のゲッターとセッターの価値を理解しています。ただし、単に値を渡すだけの場合は、不必要に冗長に見えます。
私は同意する傾向がありますが(これは不必要に冗長に見える)、これは私たちのチームがまだ解決していない問題であるため、コーディング標準はすべてのクラスの冗長プロパティを主張しています。
Jeff Atwood 数年前にこれに対処しました。彼が振り返って指摘した最も重要な点は、フィールドからプロパティへの変更は、コードの breaking change であるということです。それを消費するものはすべて、新しいクラスインターフェイスで動作するように再コンパイルする必要があります。そのため、コントロール外のものがクラスを消費している場合、問題が発生する可能性があります。
後でこれに変更するのも簡単です。
public int x { get; private set; }
これらのメンバーの設定とアクセスをカプセル化します。メンバーのアクセスまたは設定時にコードの開発者がロジックを変更する必要がある場合、クラスのコントラクトを変更せずにそれを行うことができます。
基本的なデータ構造を変更する必要がある場合でも、クラスへのパブリックインターフェイスを変更する必要がないという考え方です。
C#は、プロパティと変数を時々異なる方法で処理できます。たとえば、 refまたはoutパラメータとしてプロパティを渡すことはできません 。したがって、何らかの理由でデータ構造を変更する必要があり、パブリック変数を使用していてプロパティを使用する必要がある場合、インターフェイスを変更する必要があり、プロパティxにアクセスするコードは変数のときのようにコンパイルできなくなる可能性がありますバツ:
Point pt = new Point();
if(Int32.TryParse(userInput, out pt.x))
{
Console.WriteLine("x = {0}", pt.x);
Console.WriteLine("x must be a public variable! Otherwise, this won't compile.");
}
最初からプロパティを使用することでこれを回避でき、クライアントコードを壊すことなく、必要なだけ基になる実装を自由に調整できます。
自動実装されたゲッターは、プロパティと実際のプライベートストレージ変数に同じ名前を使用するためです。将来どのように変更できますか?言われているポイントは、フィールドの代わりに自動実装を使用して、ゲッターとセッターにロジックを追加する必要がある場合に将来変更できるようにすることだと思います。
例えば:
public string x { get; set; }
たとえば、xをすでに何度も使用しているため、コードを壊したくない場合。
自動ゲッターセッターを変更するにはどうすればよいですか?たとえば、セッターでは有効な電話番号形式のみを設定できます...クラスのみが変更されるようにコードを変更するにはどうすればよいですか?
私のアイデアは、新しいプライベート変数を追加し、同じxゲッターとセッターを追加することです。
private string _x;
public string x {
get {return x};
set {
if (Datetime.TryParse(value)) {
_x = value;
}
};
}
これは、柔軟にするという意味ですか?
SetterおよびGetterを使用すると、追加の抽象化レイヤーを追加できます。純粋なOOPでは、外部の世界に提供しているインターフェイスを介して常にオブジェクトにアクセスする必要があります...
このコードを検討してください。これにより、asp.netに保存され、setterおよびgetterによって提供される抽象化レベルがなければ不可能になります。
class SomeControl
{
private string _SomeProperty ;
public string SomeProperty
{
if ( _SomeProperty == null )
return (string)Session [ "SomeProperty" ] ;
else
return _SomeProperty ;
}
}
また、バインディングおよびシリアル化に関しては、パブリックメンバーへの変更の影響も考慮する必要があります。多くの場合、これらは両方ともパブリックプロパティに依存して値を取得および設定します。
また、ゲッターとセッターにブレークポイントを置くことはできますが、フィールドにはできません。
また、自動プロパティを読み取り専用にすることはできず、インラインで初期化することはできません。これらはどちらも.NETの将来のリリースで見たいものですが、.NET 4.0ではどちらもできないと思います。
最近、プロパティでバッキングフィールドを使用するのは、クラスがINotifyPropertyChangedを実装し、プロパティが変更されたときにOnPropertyChangedイベントを発生させる必要がある場合だけです。
また、これらの状況では、コンストラクターから値が渡されるときにバッキングフィールドを直接設定します(OnPropertyChangedEvent(この時点ではいずれにしてもNULLになる)を試行する必要はありません)。
知る限り、生成されたCILインターフェイスは異なります。パブリックメンバーをプロパティに変更すると、そのパブリックインターフェイスが変更され、そのクラスを使用するすべてのファイルを再構築する必要があります。ゲッターとセッターの実装のみを変更する場合、これは必要ありません。
フィールドを公開するだけで、より多くの Anemic Domain Model に導くことができます。
敬具
後でデータを翻訳する必要がないかどうかはわかりません。メンバーを隠せば、そのための準備ができています。インターフェースは同じままなので、クラスのユーザーは翻訳を追加しても気付かないでしょう。
最大の違いは、内部構造を変更した場合でも、ゲッターとセッターをそのまま維持でき、APIのユーザーを傷つけることなく内部ロジックを変更できることです。
この場合、xとyの取得方法を変更する必要がある場合は、後でプロパティを追加するだけで済みます。これは私が最も紛らわしいと思うものです。パブリックメンバ変数を使用する場合、後でプロパティに簡単に変更できます。また、値を内部に保存する必要がある場合は、_xおよび_yというプライベート変数を使用できます。