FIELDSに対するPROPERTIESの利点は理解していますが、MANUAL実装プロパティよりもAUTO実装プロパティを使用しても、コードを少し簡潔にして見るだけで、実際には何の利点もないように感じます。
私は使用してはるかに快適だと感じています:
private string _postalCode;
public string PostalCode
{
get { return _postalCode; }
set { _postalCode = value; }
}
の代わりに:
public string PostalCode { get; set; }
主な理由は、getおよびsetの任意の種類のカスタム実装を実行したい場合は、とにかくプライベートフィールドに基づく独自のプロパティを作成する必要があるためです。それでは、一貫性を保つために、最初から弾丸を噛み、すべてのプロパティにこの柔軟性をすぐに与えないのはなぜですか?これには本当に時間がかかりませんが、Visual Studioで行う必要があるのはプライベートフィールド名をクリックしてCtrl + Eを押すだけでよいので、もう少し時間がかかります。また、手動で実行すると、プライベートフィールドに基づく手動で作成されたパブリックプロパティと自動実装されたプロパティが存在するという矛盾が生じます。全自動または全手動のいずれかで一貫しているので、ずっと気分が良くなります。
これは私だけですか?何か不足していますか?何か間違えていますか?一貫性を重視しすぎていますか?私は常にC#機能についての正当な議論を見つけることができ、ほとんどすべてに賛否両論がありますが、この場合、自動実装されたプロパティの使用を推奨しない人を見つけることはできませんでした。
それはあなたが簡潔であること以上にあなたに何かを与えることはありません。より詳細な構文を使用する場合は、必ずそれを使用してください。
Autoプロップを使用する利点の1つは、間違ったプライベート変数を誤ってプロパティに割り当ててしまうなど、愚かなコーディングの間違いを防ぐことができることです。私を信じて、私は以前にやったことがある!
自動車の小道具があまり柔軟でないというあなたの主張は良いことです。あなたが持っている唯一の柔軟性は、private get
またはprivate set
スコープを制限します。ゲッターまたはセッターが複雑な場合、自動小道具はもはや実行可能なオプションではありません。
自動実装プロパティは、ビルド間で同じバッキングフィールド名を保持することは保証されていません。したがって、理論的にアセンブリの1つのバージョンでオブジェクトをシリアル化してから、その同じオブジェクトを別のアセンブリで再シリアル化すると、重大な変更が発生する可能性があります。
これはhighlyありそうもないことですが、アセンブリのバージョンを新しいバージョンに「スワップアウト」する機能を維持しようとしている場合、これは有効な懸念事項です。
手動で実装されたプロパティを使用することにより、バッキングフィールドが変更されないことが保証されます(特に変更しない限り)。
そのわずかな違いは別として、自動プロパティはバッキングフィールドで自動的に実装される通常のプロパティです。
私は他の人については知りませんが、他の人が私のコードを理解できるように、私はvariablesとfunctionsという名前を付けるべきか少し考えるのを止める傾向があります。
したがって、auto-implementedプロパティを使用すると、一時停止する必要があるのは1回だけになります。
バッキングフィールドが必要な場合2回一時停止する必要がありますなので、開発が少し遅くなります:)
私のやり方は:
クラスの異なるプロパティが異なる方法で公開されていても問題はありません。
制御できなくなることの1つは、バッキングフィールドをNonSerializedとして指定する機能ですが、この場合、プロパティのバッキングフィールドを作成するのは簡単です。
忘れた:自分または使用している製品がメンバー(つまり、WCF)でリフレクションを実行する場合、作成した「かなり」のバッキングフィールドではなく、壊れたバッキングフィールド名が表示されます。
これは、以前にサービスへのアクセスを提供していた場合、または受信側で同じクラス構造に逆シリアル化する場合(つまり、同じクラスがWCFパイプの両端で使用される場合)に非常に重要です。この場合、ソースコードではなく同じDLLを共有しない限り、バッキングフィールド名が同じであることを保証できるため、必ずしも逆シリアル化できるとは限りません。
もう少し明確にします。WCFを介してビジネスオブジェクトの一部を、作成したSilverlightクライアントに公開するWebサービスがあるとします。ビジネスロジックを再利用するために、Silverlightクライアントはビジネスオブジェクトのソースコードへの参照を追加します。自動実装プロパティがある場合、バッキングフィールド名を制御できません。 WCFはプロパティではなくメンバーをシリアル化するため、バッキングフィールド名がほぼ確実に一致しないため、WCFサービスからSilverlightに転送されたオブジェクトが正しく逆シリアル化されるとは限りません。
自動プロパティは多少悪である可能性があると考えています ですが、それ以外は単なる構文上の砂糖です。数行のコードを保存する以外にそれらを使用しても何も得られず、潜在的に自分のためにより多くの作業を作成することができます(後で何らかのチェックを行うかイベントを発生させたいので、とにかく手動で実装する必要があるため)。一貫性はプログラミングにおいて非常に貴重です(imho)。
自動プロパティを使用する利点の1つは、アプリケーションのデバッグ中不要なGet/Setセクションにステップインしません。デバッガー属性またはステップオーバーを使用して同じことを回避できることを知っています。ただし、大規模なアプリケーションでデバッグを行うと、ほとんどの場合に発生します。
私は常にC#機能についての正当な議論を見つけることができ、ほとんどすべてに賛否両論がありますが、この場合、自動実装されたプロパティの使用を推奨しない人を見つけることはできませんでした。
今日のコードレビューでこの質問に出くわしましたが、同僚グループに質問したところ、合意に達することができませんでした。私はあいまいさを嫌い、あなたの質問に答える少なくとも1つの燃える質問を知りたかったのです。
Tootsie Roll Tootsie Popの中心に到達するまでに何回なめる必要があるかを調べるのと同じように、「調べてみる」ことにしました。
最初に実際にリンゴとリンゴの比較をしてみましょう。
次の2つのクラスがあるとします。
public class C
{
private int z;
public int Z
{
get { return z;}
}
}
public class Q
{
public int Z { get; }
}
最初のクラスは手動バッキングストア、2番目のクラスは自動コンパイラが生成したバージョンです。
それぞれについて生成されたILを見てみましょう。
まず、バッキングストアの手動バージョン:
// Fields
.field private int32 z
// Methods
.method public hidebysig specialname
instance int32 get_Z () cil managed
{
// Method begins at RVA 0x2050
// Code size 12 (0xc)
.maxstack 1
.locals init (
[0] int32
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld int32 C::z
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of method C::get_Z
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2068
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method C::.ctor
// Properties
.property instance int32 Z()
{
.get instance int32 C::get_Z()
}
次に、2番目のクラスのILを見てみましょう。
// Fields
.field private initonly int32 '<Z>k__BackingField'
.custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [System.Private.CoreLib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Private.CoreLib]System.Diagnostics.DebuggerBrowsableState) = (
01 00 00 00 00 00 00 00
)
// Methods
.method public hidebysig specialname
instance int32 get_Z () cil managed
{
.custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2071
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 Q::'<Z>k__BackingField'
IL_0006: ret
} // end of method Q::get_Z
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2068
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Q::.ctor
// Properties
.property instance int32 Z()
{
.get instance int32 Q::get_Z()
}
かなりの実行可能コードを追加しないデバッグ可能な属性を追加するための追加のコンパイラー生成コードを無視すると、生成コードに差異はありません。
さて、あなたはあなたの質問が答えられていないと主張するかもしれませんが、考慮してください...
次のようなバインディングに参加するプロパティをコーディングしたことがある場合:
private string name;
public string Name
{
get { return name; }
set { SetProperty (ref name, value);
}
次に、バッキングストアが実行されます。
一方、Visual Studioエディターで「prop」<TAB> <TAB>ショートカットを使用して自動プロパティを生成するのは非常に便利で、よりもはるかに高速です。 allそのタイピング;)
結局、ハンマーにとって、すべてが釘のように見えます。ハンマーにならないでください。