web-dev-qa-db-ja.com

クラスに常にデフォルトのコンストラクタを含める必要がありますか?

同僚からこの質問をされましたが、常にクラスにデフォルトコンストラクターを含める必要がありますか?もしそうなら、なぜですか?いいえの場合、なぜですか?

public class Foo {

    Foo() { }

    Foo(int x, int y) {
        ...
    } 

}

また、専門家からこれに関するいくつかのライトを入手することに興味があります。

66
Moon

オーバーロードされたコンストラクターを提供しない場合、コンパイラーがデフォルトのコンストラクターを生成することに注意してください。つまり、あなたが持っているだけなら

_public class Foo
{ 
} 
_

コンパイラはこれを次のように生成します。

_public class Foo
{ 
    public Foo() { }  
} 
_

ただし、他のコンストラクタを追加するとすぐに

_public class Foo
{ 
    public Foo(int x, int y)
    { 
        // ... 
    }  
} 
_

コンパイラはデフォルトのコンストラクタを自動的に生成しなくなりました。クラスがデフォルトのコンストラクタFoo f = new Foo();の存在に依存する他のコードで既に使用されていた場合、そのコードは壊れます。

データを提供せずにクラスを初期化できるようにしたくない場合は、privateであるデフォルトコンストラクターを作成して、入力データなしでインスタンスが構築されないようにすることを明示する必要があります。

ただし、デフォルトのコンストラクタ(パブリックまたはプライベート)を提供する必要がある場合があります。前述したように、一部の種類のシリアル化にはデフォルトのコンストラクターが必要です。クラスには複数のパラメーター化されたコンストラクターがありますが、「下位レベル」の初期化も必要な場合もあります。この場合、パラメーター化されたコンストラクターからチェーンされたプライベートデフォルトコンストラクターを使用できます。

_public class Foo
{
   private Foo()
   {
      // do some low level initialization here
   }

   public Foo(int x, int y)
      : this()
   {
      // ...
   }

   public Foo(int x, int y, int z)
      : this()
   {
      // ...
   }
}
_
110
Scott Dorman

いくつかのこと(シリアル化など)にはデフォルトのコンストラクターが必要です。ただし、それ以外では、デフォルトのコンストラクタは、意味がある場合にのみ追加する必要があります。

たとえば、Foo.XおよびFoo.Yプロパティは構築後は不変であり、デフォルトのコンストラクターは実際には意味がありません。 '空の' Fooに使用されたとしても、静的なEmptyアクセサーはより発見しやすいでしょう。

19
Richard Szalay

私は言うno、間違いなくalways。何らかの値に初期化する必要があるいくつかの読み取り専用フィールドを持つクラスがあり、妥当なデフォルトが存在しないと仮定します(または、存在させたくない)。このシナリオでは、パラメーターなしのコンストラクターが意味をなさないと思います。

12
Dan Tao

デフォルトのコンストラクタを使用するのは、そのようなオブジェクトを使用することが理にかなっている場合にのみ有効です。

このようなコンストラクターから有効な状態にないオブジェクトを作成する場合、できることはバグを導入することだけです。

5
Jon Hanna

はい混乱を避けるために、デフォルトのコンストラクタを配置することをお勧めします。デフォルトのコンストラクター内では(Microsoft自身のクラスであっても)何もしないだけですが、オブジェクトが自動的にdefault(type)を取得するので、それを維持したいのです。デフォルトのコンストラクタを指定しないクラス。NETは自動的にそれらを追加します。

既存のシリアライザーを使用する場合、汎用シリアライザーに意味があるため、シリアル化にはデフォルトコンストラクターが必要です。そうでない場合は、独自の実装を作成する必要があります。

1
abhishek

サイドノートとして、クラスの代わりに構造体を使用する場合、デフォルトのコンストラクタを除外する方法なしがあることに注意してください。また、自分で定義することもできないため、定義するコンストラクタに関係なく、make構造体のデフォルト状態(すべての変数がデフォルト状態(通常、値型の場合は0、参照型の場合はnull)に設定されている場合)が構造体の実装を壊さないことを確認してください。

1

ほとんどの場合、デフォルトのコンストラクターをお勧めします。ただし、「常に」という言葉を使用するため、必要なのは1つの反例だけです。フレームワークを見ると、たくさんあります。たとえば、System.Web.HttpContext。

0
Joe

ジェネリック型は、デフォルトのコンストラクターがある場合にのみ、C#の手段(リフレクションなし)でインスタンス化できます。また、new()ジェネリック型制約を指定する必要があります。

void Construct<T>()
    where T : new()
{
    var t = new T();
    ...
}

デフォルトのコンストラクタを持たないジェネリック型引数として型を使用してこのメ​​ソッドを呼び出すと、コンパイラエラーが発生します。