.NETでは、値型(C# struct
)はパラメータのないコンストラクタを持つことができません。この郵便受けこれは CLI 仕様によって義務付けられています。すべての値型に対して、すべてのメンバーをゼロ (または ) に初期化するデフォルト コンストラクターが (コンパイラによって?) 作成されますnull
。
なぜこのようなデフォルト コンストラクターを定義することは許可されないのでしょうか?
1 つの簡単な使用法は有理数の場合です。
public struct Rational {
private long numerator;
private long denominator;
public Rational(long num, long denom)
{ /* Todo: Find GCD etc. */ }
public Rational(long num)
{
numerator = num;
denominator = 1;
}
public Rational() // This is not allowed
{
numerator = 0;
denominator = 1;
}
}
現在のバージョンの C# を使用すると、デフォルトの Rational は0/0
あまりクールではありません。
PS : C# 4.0 では、デフォルト パラメーターがこの問題を解決するのに役立ちますか、それとも CLR 定義のデフォルト コンストラクターが呼び出されますか?
ジョン・スキート答え:
あなたの例を使うと、誰かが次のことをしたときに何が起きることを望みますか:
Rational[] fractions = new Rational[1000];
コンストラクターを 1000 回実行する必要がありますか?
もちろんそうすべきです。それが、私が最初にデフォルト コンストラクターを書いた理由です。明示的なデフォルト コンストラクターが定義されていない場合、CLR はデフォルトのゼロ化コンストラクターを使用する必要があります。そうすれば、使用した分だけ支払うことになります。次に、1000 個の非デフォルトのコンテナーが必要な場合Rational
(および 1000 個のコンストラクションを最適化したい場合は)、配列ではなく を使用しますList<Rational>
。
私の考えでは、この理由は、デフォルト コンストラクターの定義を妨げるほど強力ではありません。
ベストアンサー1
注:
以下の回答は、構造体にパラメータなしのコンストラクタを宣言する機能を導入する予定のC# 6よりずっと前に書かれたものですが、それでもすべての状況で呼び出されるわけではありません(配列の作成など)
(最終的にこの機能はC# 6には追加されなかった)...しかし、それは C# 10 で追加- ただし、制限があるため、あらゆる状況でコンストラクターが実行されるとは限りません。
編集: Grauenwolf の CLR に関する洞察に基づいて、以下の回答を編集しました。
CLR では値型にパラメータなしのコンストラクターが許可されていますが、C# では許可されていません。これは、コンストラクターが呼び出されないときに呼び出されるという期待が生じるためだと考えられます。たとえば、次の例を考えてみましょう。
MyStruct[] foo = new MyStruct[1000];
CLR は、適切なメモリを割り当ててすべてをゼロにするだけで、これを非常に効率的に実行できます。MyStruct コンストラクターを 1000 回実行する必要がある場合、効率が大幅に低下します。(実際にはそうではありません。パラメーターなしのコンストラクターがある場合、配列を作成するときや初期化されていないインスタンス変数があるときは実行されません。)
C# の基本的なルールは、「どの型のデフォルト値も、どの初期化にも依存できない」というものです。パラメータなしのコンストラクタを定義できるようにして、そのコンストラクタをすべての場合に実行することを要求しないようにすることもできましたが、そうすると混乱がさらに増すことになります。(少なくとも、議論はそうであると私は信じています。)
編集: あなたの例を使うと、誰かが次のことをしたときに何が起きることを望みますか:
Rational[] fractions = new Rational[1000];
コンストラクターを 1000 回実行する必要がありますか?
- そうでなければ、1000個の無効な有理数になってしまう。
- そうなる場合、配列に実際の値を入力しようとして、大量の作業を無駄にしてしまう可能性があります。
編集: (質問にもう少し答えます) パラメータなしのコンストラクタはコンパイラによって作成されません。CLR に関する限り、値型はコンストラクタを持つ必要はありませんが、 IL で記述する場合はコンストラクタを持つことができます。C# で " " と記述すると、new Guid()
通常のコンストラクタを呼び出した場合とは異なる IL が生成されます。このSOの質問その点についてもう少し詳しく説明します。
フレームワークには、パラメータなしのコンストラクタを持つ値型は存在しないのではないかと思います。丁寧に尋ねれば、NDepend が教えてくれるはずです... C# がそれを禁止しているという事実は、それがおそらく悪い考えであると考えるのに十分なヒントです。