2009-04-09 10 views
6

私はC#2.0で作業していますが、これはほとんどのオブジェクト指向言語に当てはまります。プライベートフィールドをラップするパブリックプロパティを持つクラスを作成するときは、内部でプロパティまたはフィールドを使用するかどうかを、&に戻します。もちろん、C#3.0では自動プロパティでこれを簡単に行えますが、それでも適用できます。OOデザイン - パブリックプロパティまたはプライベートフィールドを内部的に使用していますか?

重要ですか?

public class Person 
{ 
    private string _name = ""; 

    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public Person(string name) 
    { 
     _name = name; //should I use the property or field here? 
    } 
} 

答えて

2

大抵それは、コードの好みのようだが、私は」パブリックプロパティまたはこれまでプライベートプロパティを使用することを好む、あなたは単に、呼び出し元のコードを変更することなくプロパティにいくつかのロジックを追加することができます。また、3.5 .NETでは、自動作成機能として便利なコードの砂糖があります。

2

私はあなたの財産の中で何かをやっているかも知れません。怠惰な読み込み、変換、書式設定、計算など、プライベートメンバーを使用した場合にバグが発生する可能性があります...

0

通常、私はいくつかの例外を除いてパブリックプロパティを使用します。プロパティアクセサー。 C#3.0の自動プロパティでは、手作業でフィールドを作成することはめったにありません。通常、自動バッキングフィールドのデフォルト値が自分のプロパティに適切でない場合にのみ使用されます。

0

少なくともJavaでは、皆さんが使用しているような古いjavabeansの表記規則のため、パブリックフィールドを使用する方法はありません。 私はC#が最初の言語の構成としてプロパティを持っていると思います。私はそれに行くだろう

+1

はい、それはC#の大きな利点です。 – Randolpho

+0

これらのjavabeanerのものを知らない私たちのもののために何が起きているのですか? –

+1

あなたはそれを自分で正当化できない場合は特に、「誰もがそれらを使用しているように見える」という理由だけで慣習に従うべきではありません。条約は、それが良い考えであることを意味するものではありません。それに質問してください! :) – JoshJordan

0

あなたはこの値のいくつかのチェックをしたい場合は、 "名前"プロパティの設定者に配置することができますし、最近のために使用されるため、あなたは "名前"(プロパティ)設定値も。

1

プロパティを使用します。あなたはそのようにC#3.0、または使用上の自動プロパティを使用している場合や、より良いまだ、:

public class Person 
{ 
    public string Name { get; set; } 

    public Person(string name) 
    { 
     Name = name; //should I use the property or field here? 
    } 
} 

あなたが今プロパティを使用している場合は、自動プロパティを使用するようにコードを変更すると、あなたは準備ができていますよ。

14

基本的に、検証やその他のロジックをプロパティに実装できるため、そうでない特別な理由がない限り、プロパティを介してアクセスする必要があります。

これは、オブジェクト内の一貫性を保つのに役立ちます。これは、プライベートフィールドの値がアクセサーまたはセッターメソッドに設定する任意の厳密さを超えていることを知っているからです。

一方、初期値の設定が必要な場合があるため、コンストラクタは例外である可能性があります。

しかし、一般的には、私はプロパティを介してアクセスを言うだろう。

EDIT

A(些細/不自然)の例

public class Person 
{ 
    private string _name = ""; 
    private List<String> oldnames = new ArrayList(); 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      oldnames.Add(_name); 
      _name = value; 
     } 
    } 

    public Person(string name) 
    { 
     _name = name; //should I use the property or field here? 
    } 
} 

だから、この場合には、プロパティをスキップするコンストラクタをしたいだろうが、あなたは二度とフィールドを使用する場合は、よ「名前のアーカイブ」をスキップしているため、コードにバグが発生する可能性があります。プロパティに検証を入れる理由は、フィールドにアクセスするすべての場所で検証コードを複製する必要がないため、非公開のメソッドでもスキップしないでください。

+0

私はJavaとC#が異なる言語であることを指摘しておかなければならないと思います。 C#にはプロパティがあり、Javaではそうではありません。 – epochwolf

+0

このフィードバックを組み込むために私の答えを編集するにはどうすればよいですか? – DevinB

+0

ああ、私は、ええ、私はJavaに関連していると思った何らかの理由でええ、参照してください。 – DevinB

0

です。時には、フィールドとの現実的なやりとりのために重要な前処理を行うgetters/setterを記述します。たとえば、文字列フィールドに常に小文字でなければならない制約がある場合、getter/setterメソッドの少なくとも1つは.ToLower()または.ToLowerInvariant()を呼び出す必要があり、クラスコードではおそらくこれを使用して、制約が強制されていることを確認します。

ただし、前処理ロジックを回避する必要がある場合もあります。実際、開発者が私的なフィールドではなく公的なプロパティを使用することによって無意識に無限ループを作成しているのを見てきました(私の頭の上の例を考えることはできません)。

Linqプロパティにどれくらいの論理が存在するかを示すため、SQLの生成クラスは良い例です。いくつかの拡張メソッドを書こうとすると、違いを理解し始めるでしょう。

私は、クラスの任意のポイントでどのようなロジックを使用しているのか、getters/setterにどのような前処理があるのか​​によって決まると思います。もしあなたが確信が持たれていない、またはそれが問題ではないように思われるなら、getters/setters/publicプロパティを使用して、後で追加される制約に従う保守可能なコードを書く方が良いでしょう。

1

フィールドに内部的にアクセスする必要がある場合があります。たとえば、プロパティへの読み取り専用アクセスのみを公開し、オブジェクトのインスタンス化後に変更を許可する値は公開しません。

public class MyClass 
{ 
    private string _MyProperty; 

    public MyProperty { get { return _MyProperty; } } 

    public MyClass() 
    { 
     _MyProperty = SomeVeryComplexPropertyInitializationLogic(); 
    } 
} 
1

フィールド名を使用すると、カプセル化されません。カプセル化は、クラス間だけでなくクラス内でも適用されます。

将来的にフィールドを再定義するが、アクセサー/セッター関数のシグネチャを同じままにしておくと、クラスを使用する外部クラスが中断しないだけでなく、自分のクラスの内部ルーチンも中断しない。

緩くにApache Wicketのフレームワークに表示コードに基づいて、例えば、このコードを取る(フレームワークは、この問題を受けませんが、私はちょうどそれが示して使用しています):

をのは、これがいたとしましょう元のクラス:ここ

class RadioChoice { 
    private String prefix; 

    RadioChoice(String prefix) { 
    this.prefix = prefix ; 

    setPrefix(String prefix) { 
    this.prefix = prefix ; 
    } 
} 

我々はすでに問題を見ることができます。同じ操作this.prefix = prefixは、トウの場所で起こります。これはまったく同じことを意味しますが、2つの場所で発生するため、同じことが2つの異なるものに分岐する可能性があります。

Apache Wicketには、Webページのレンダリング方法の変更を記録するというコンセプトがあり、変更を元に戻すことができます。これは、 "元に戻す"オブジェクトのリストを格納することで行います。 RadioChoiceの接頭辞を元に戻すことができ、そのため「プレフィックス」セッターが変更を記録しなければならないものの一つです:

class RadioChoice { 
    private String prefix; 

    RadioChoice(String prefix) { 
    this.prefix = prefix ; 

    setPrefix(String prefix) { 
    // save the old prefix 
    this.getPage().addChange(new PrefixChange(this.prefix)); 
    // set the new one 
    this.prefix = prefix ; 
    } 
} 

は今、何が起こるか見て:コンストラクタは直接プレフィックスを設定しているため、何の変化がで保存されませんctor。セッターを使用した場合、リファクタリングの後、ctorは自動的に「正しいことをする」でしょう。代わりに、セッターの両方をリファクタリングする必要があります。もちろん

、我々のコードはまだ最適ではない、現実には、このする必要があります。

setPrefix(String prefix) { 
    // save the old prefix 
    this.getPage().addChange(new PrefixChange(this.getPrefix())); 
    // set the new one 
    this.prefix = prefix ; 
    } 
} 

スコット・マイヤーズ氏は、(C++のことを提唱したこの記事のシリーズを、持っていました、 (プリミティブ関数:はクラスiteslf以外では機能できません)、プリミティブ関数から構成できるすべての関数を自由な関数にすることができます。これは、よりリーンなインターフェース、より安定したインターフェースを可能にする。

同じように、クラス内の関数をプリミティブインターフェイスにのみ依存するように扱える範囲で、柔軟性が増します。特に、それらの機能は、クラスから移動される候補である。より一般的には、setterとgetterを使用すると、変更を防ぐことができます。

関連する問題