2009-05-14 14 views
27

私はC#で新しいオブジェクトを構築するのに好ましい方法は何でしょうか?C#でオブジェクトを構成する好ましい方法は何ですか?コンストラクタのパラメータまたはプロパティ?

はPersonクラスを取る:

public class Person 
{ 
    private string name; 
    private int age; 

    //Omitted.. 
} 

は、私はそれを使用するために作成する必要があります。

New Person("name", 24); 

または

New Person() { Name = "name", Age = 24 }; 

それは単なる好みの問題ですか良いがありますもう一方を使う理由?

コンストラクタの必須フィールドとコンストラクタパラメータではなくプロパティを使用するオプションフィールドを使用する必要があると思います。

私はそうですか?

+2

これは事実上C#版のhttp://stackoverflow.com/questions/830657 –

答えて

39

好ましい方法は、デザインによって異なります。

コンストラクタプロパティは、オブジェクトが正しく構築されるために必要なアイテム用です。つまり、オブジェクトを初期化するために必要なすべてのプロパティはコンストラクタ内にある必要があります(ファクトリまたはビルダーパターンを作成しない限り、コンストラクタが呼び出された後に部分的に初期化されたオブジェクトは通常必要ありません。コンストラクタはファクトリ/ビルダー以外のすべてから隠されています)。

プロパティの初期化は、特定のユースケースで必要とされるが、オブジェクトが初期化されているとはみなされないコンストラクターの後の追加の設定に最適です。

たとえば、人物を表すオブジェクトを持つことができます。人は名前と年齢が必要ですが、住んでいる住所はオプションです。したがって、名前と年齢はコンストラクタパラメータであり、アドレスは読み書き可能なプロパティです。プロパティを手動設定について

Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" }; 
+0

これは、いつ何を適用するのかを識別するのに役立つ非常に良い根拠です。ありがとう! – Peterdk

+0

マーク・グラヴェルの答え(http://stackoverflow.com/a/863064/23234)を読むことをお勧めします。このシナリオでは、私が提示した理想的な視点が他の制約のために適切でない実際の使用法を見ています。 –

2

第二の方法は、手動でプロパティを設定するための単なる糖衣構文です:

Person p = new Person(); 
p.Name = "name"; 
p.Age = 24; 

また、あなたは設定したいすべてのプロパティをinitalizeないかもしれないコンストラクタに依存していません。

クラスにこれらの2つのパラメータを必要とするコンストラクタがある場合、そのコンストラクタを明示的に呼び出すことはありません。

12

実際にはシナリオによって異なります。プロパティのアプローチはコンストラクタ内の代入を複製する必要がないため、多くの利便性があります。さらに、ほとんどのデータバインディングシナリオでは、新しいオブジェクトを作成することができます。新しいオブジェクトは、通常はパラメータのないコンストラクタを使用するため、大きな利点です。

しかし、不変型の場合、コンストラクタのアプローチは唯一の選択肢です。興味深いことに(恐らく)、C#4.0の名前付き/オプションのパラメータは、不変型のオブジェクトインサイタイザに似たものを許可しています - see here

コンストラクタのアプローチは、Inversion of Controlフレームワークでも非常に一般的です。これは、そのクラスが機能するために必要なものを明確に宣伝するためです。

コンポーザースタイルよりもプロパティースタイルを混在させる必要があります。

+2

はい - 読み取り専用フィールドはコンストラクタコードによってのみ設定できます。 – Dario

5

コンストラクタの値を設定すると、これらのプロパティが必須になります。つまり、これらのプロパティを設定せずに新しいインスタンスを作成することはできません。 状況によってはこれが望ましい場合もありますが、他の状況ではこれが優先されません。

+0

これは本当ですが、構造体の場合は必須ではありません。 – Noldorin

+0

実際、構造体は値型であり、初期化されていなくても常に(デフォルト)値を持つためです。 –

0

この質問に関する主な考慮事項は、1)オブジェクトがインスタンス化されたときにインスタンス化エンティティが持つデータ量と、2)カプセル化されたクラスがどのように必要なのか?一度設定するとプロパティが変更できないようにする必要があります(少なくとも外部のエンティティのため)、コンストラクタは任意の読み取り専用プロパティと読み取り/書き込みプロパティを設定できるので、コンストラクタを使用します。

他のメソッドと同じように、コンストラクタをオーバーロードすることができるので、これらのプロパティを初期化する方法をいくつでも設定できます。

一般に、コンストラクタを使用しますが、プロパティを手動で設定することがあります。適切な問題に適切なツールを使用してください。

7

私は常に、そのオブジェクトが有効な状態に存在するために必須のコンストラクタに値を渡す必要があるということに基づいて作業します。

例では、新しい人物が年齢なしで存在することができないので、コンストラクタに渡す必要があります。

オブジェクトが実際の作業エンティティをモデル化する必要があることに基づいて作業する場合、オブジェクトをデフォルト値として設定するか、コンストラクタ経由で値を渡すかによって、オブジェクトを有効にするために必要な最小値が決まります。

+1

+1:オブジェクトは、構築後および各メソッド呼び出しの後で常に有効な状態にしておく必要があります。メソッドは実行前に独自のオブジェクトの状態を検証する必要はなく、引数だけを検証します。 – palm3D

2

私の意見では、まず人を何にするのかを決めるべきです。人物オブジェクトが正しくインスタンス化されるための人物のプロパティは何ですか?人の最低要件は何ですか?

最小要件を持つコンストラクタが常に存在する必要があります。

インスタンス化するプロパティを必要としない型に対してのみ、オブジェクト初期化子を使用します。したがって、デフォルトのコンストラクタです。

私は、オブジェクト初期化子が非常に便利であることを知っています。他のメカニズムでは、オブジェクトに空のコンストラクタが必要な場合もあります。

しかし私はあなたが名前のない人を作ることができるとは思えません。

4

いくつかの考え:

  1. あなたはオブジェクト初期化子を使用してパブリックプロパティを必要とします。したがって、公開したくないものがある場合は、コンストラクタパラメータで初期化する必要があります。

  2. ILをチェックすると、Object Initializerが「アトミック」ではないことがわかります。あなたは(私は、ちょうど例をお勧めしないこと)、このようなコードを記述する場合:

    using (p = New Person() {Name = GetName(), Age = GetAge()}) 
    { 
        //blah, blah 
    } 
    

    GetAge()で例外がある場合、あなたは、破損した状態でPersonのインスタンスを作成します。さらに悪いことに、使用範囲に入ることは決してできず、そのインスタンスはあなたが想像するように処分されることはありません。

+0

私はそれが原子ではないことを指摘したのが好きです。あなたがそれを見たときに明白であり、私があなたが書いたようにコードを書くとは思わないが、他の誰かのコードを読んでいたなら、私はそれを拾ったとは思わない。 –

0

、彼らは公共の宣言されなければならないだろう、とあなたは、クラスメンバーがプライベートになりたいことがあります。その場合、コンストラクタは、それらを取得/設定するメソッドやアクセッサを使用するメソッドを記述するための方法です。

0

私は、プロパティ初期化子を持つ非常に単純なコンストラクタを好む傾向があります。私はそれがより明示的なコードにつながることを発見します。私がコンストラクタに渡す唯一のデータは、クラスが作成されるとクラスのユーザが変更したくないという情報です。

0

実際の問題は、層/レイヤーでオブジェクトを渡すときに発生します。たとえば、personオブジェクトを作成し、webserviceをパスします。 somepointのwebserviceはデシリアライズを試み、インスタンス化しようとしますが、コンストラクタに必要なパラメータがある場合はエラーが発生する可能性があります。 Webサービスは最初にオブジェクトを作成し、次に値を割り当てます。

したがって、階層を通過する必要があるデータモデル(POCOソート)の場合は、パラメータのないコンストラクタを使用することをお勧めします。

他の理由で、コンストラクタパラメータが(必須フィールドの場合)最善の方法です。特にクラスを外部オブジェクトやアセンブリのイタフェイスとして提供する場合。

関連する問題