2012-05-31 6 views
18

私はこのようなクラスがある場合:私は、クラスをファクタし直すかの段階で1つのコンストラクタが別のコンストラクタを実装すると、利点や欠点はありますか?

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    public Foo() 
    { 
     Bars = new List<Bar>(); 
    } 
} 

をし、このような最初のものを実装して、二次のコンストラクタを追加:

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    // some more properties were added 

    public Foo() 
    { 
     Bars = new List<Bar>(); 
    } 

    public Foo(string parameter): this() 
    { 
     .... some code here 
    } 
} 

を私も持っている可能性があり

public class Foo 
{ 
    public IEnumerable<Bar> Bars { get; set; } 

    // some more properties were added too 

    public Foo() 
    { 
     InitilizeFoo(); 
    } 

    public Foo(string parameter) 
    { 
     InitilizeFoo(); 
     .... some code here 
    } 

    private void InitializeFoo() 
    { 
     Bars = new List<Bar>(); 
    } 
} 

このシナリオではどちらのアプローチも有効ですが、どちらか一方を使用するとメリットか欠点がありますか?

は、より効率的なconstrcutorsを継承し、そのコードを高速に実行することや、私が代わりに第2の実施の効率化を知らない欠点がありますか。

+1

私は両方を使用します。コンストラクタを連鎖させることが理にかなったら、私はそれを行います。しかし、時には(例は気にしません)私は 'InitializeFoo()'メソッドを使い、それをすべてのコンストラクタから呼び出しました。 – Nate

+0

私が心配しているのは例外の安全だけです。 –

答えて

28

1つのコンストラクタは、別のコンストラクタを呼び出す持つの重要な利点の一つは、あなたが道、あなたが非コンストラクタメソッドを呼び出すことによってそれを行うことはできません、読み取り専用のフィールドを設定することができるということです。例えば

public class Foo 
{ 
    private readonly int myNumber; 

    public Foo() : this(42) 
    { 
    } 

    public Foo(int num) 
    { 
     myNumber = num; 
    } 
} 

パフォーマンスが賢明、それは別のメソッドを呼び出すよりも、別のコンストラクタを呼び出すために、おそらく何も多かれ少なかれ、効率的ではないが、コンストラクタは、別の呼び出しすることが、私の意見では、より読みやすいですコンストラクタによって呼び出される点のみを持つ別のプライベートメソッドを呼び出すよりも、

別のメソッドを持つとき、当然のことながら、状況になる可能性があります理にかなっている、そしてそれは確かにそれ自体が「間違っている」ではありません。チェーニングコンストラクタはほとんどの用途で多くの方が読みやすく、パフォーマンスに負の影響はありません。

UPDATE:私は(プライベート初期化メソッド対チェーン)の各道の10,000,000回の反復を行い、その結果は、彼らはほとんど区別がつかなかったので、近くにあった。

Initializer Method took: 84 ms for 10,000,000 iterations, 8.4E-06 ms/each. 
Chained Constructors took: 81 ms for 10,000,000 iterations, 8.1E-06 ms/each. 

だから、本当に、性能面に近いがあるなしいずれにせよ恩恵を受ける主な利点は、readonlyフィールドを設定できる連鎖コンストラクタであり、ほとんどの場合、より読みやすくなります。

+0

迅速な対応に感謝します。私は、このデザインとほとんどのデザインのデシジョンが状況に合っていることに完全に同意しています。私の主な関心事はパフォーマンスに関するもので、コンパイルや実行時間に影響を与えました。あなたはそれをうまく対処しました、ありがとうございました。 – Nope

+2

いつでも!他のものと同様に、小さなテストを書いて、System.Diagnostics.Stopwatch()を使って数百万回の反復を測定するのは本当に簡単でしょう。 –

+0

私が適用した修正はまさにその問題でした':this()'私は修正と可能性のある効率の問題を少し心配していました。代わりに簡単なテストを書くことは考えていませんでした。それを指摘してくれてありがとう。私は確かに試してみましょう...仕事の後:)。 – Nope

4

キーが重複したコードの量を減らすことです。この場合、パラメータ化されたコンストラクタから基本コンストラクタを呼び出すと、後で両方を更新することを忘れた後にバグを追加する機会が減ります。コンストラクタの連鎖

+1

両方のコンストラクタが同じ 'Init'メソッドを呼び出す場合、この問題は既に解決されています。それはOPがコードを比較しているようだ。 – Servy

6

は、SRPとプログラムの流れを強制するための良い方法です。あなたもそれを「初期化」することがありますオブジェクトのライフサイクルにおける他の状況がある場合は、スタンドアロンInitialize()関数内で初期化コードを非表示にする意味を作ることができます。おそらく、それを素早くインスタンス化して遅延初期化できるようにしたければ、しかし、その機能を実行するためのライフサイクルの唯一の有効な時間がインスタンス化中であり、初期化が明確に定義された離散ステップのセットであれば、チェーン化はそれを容易にします。

+0

私はSRPのことは一度もありません。それは非常に良い点です。 – Nope

3

Initialize()関数を使用する利点は、オブジェクトをリセットしたい場合です。&オブジェクトを再作成するのではなく、単にinit関数を再度呼び出すことができます。

+2

+1。なぜ初期化のアプローチが有用なのでしょうか。注:私はそれを避けるためにクラスを再設計しようとしています - インスタンスが複数の他のオブジェクト間で共有されている場合、オブジェクトの状態のこのような重大な変化について通知する調整コードを提供する必要があるかもしれません。 –

+0

いいです。これは、実装する実装を決定する際に非常に役立ちます。ありがとうございました。 – Nope

2

私はこれを言ってやけどかもしれないが、私はこのケースでは、デフォルトパラメータを使用して好む:私は10だった場合持っていた

public Foo(string parameter = null) 
{ 

} 

から15のオプションのパラメータとなる15種類のコンストラクタをしません私の意見ではエレガントなソリューションです。私は、デフォルトのパラメータが4.0フレームワークでのみ再導入されたと思います。

関連する問題