1. ホーム
  2. c#

[解決済み】.NETで構造体のデフォルトコンストラクタを定義できないのはなぜですか?

2022-04-01 14:09:35

質問

.NETでは、値型(C#の場合 struct ) は、パラメータを持たないコンストラクタを持つことができません。というのも この記事 これはCLI仕様で義務付けられていることです。つまり、すべての値型に対してデフォルトのコンストラクタが作成され、すべてのメンバをゼロに初期化する(あるいは null ).

なぜ、このようなデフォルトのコンストラクタを定義してはいけないのでしょうか?

些細な使い方としては、有理数に対するものがあります。

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は デフォルトのゼロ処理 コンストラクタが明示的に定義されていない場合は、使用した分だけを支払うことになります。この場合、使用した分だけ支払うことになります。 Rational を使用します(そして、1000のコンストラクションを最適化したい)。 List<Rational> は配列ではなく

この理由は、デフォルトのコンストラクタを定義できないほど強いものではないと私は考えています。

解決するには?

<ストライク 注意 C# 6 では構造体にパラメータなしのコンストラクタを宣言できるようになる予定ですが、それでもすべての状況で呼び出されるわけではありません(例:配列の生成など)。 (最終的にこの機能 はC# 6では追加されませんでした。 ).


EDIT: Grauenwolf氏のCLRに関する見識により、以下の回答を編集しました。

CLRでは、値型にパラメータなしのコンストラクタを持たせることができますが、C#ではできません。これは、コンストラクタが呼び出されないのに呼び出されるという期待を持たせてしまうからだと思います。例えば、こんなことを考えてみてください。

MyStruct[] foo = new MyStruct[1000];

CLRは、適切なメモリを割り当て、それをすべてゼロにするだけで、これを非常に効率的に行うことができます。もし、MyStructコンストラクタを1000回実行しなければならないとしたら、それはかなり効率が悪いでしょう。(実際には、それはありません - もしあなたが する パラメータレスコンストラクタがあれば、配列の生成時やインスタンス変数の初期化時に実行されることはありません)。

C#の基本ルールは、"あらゆる型のデフォルト値は、いかなる初期化にも依存してはならない"です。現在、彼らは ができた。 パラメータレスコンストラクタを定義することは許されても、そのコンストラクタをすべてのケースで実行することは要求されません。(少なくとも、そのような議論になると思います)。

編集部:あなたの例で言うと、誰かがそうしたらどうしたいですか?

Rational[] fractions = new Rational[1000];

コンストラクタを1000回走らせるべき?

  • そうでなければ、1000個の無効な有理数で終わってしまう
  • もしそうだとすると、これから配列に本当の値を埋めようとするときに、無駄な作業をする可能性があります。

EDIT: (もう少し質問に答えると)パラメータレスコンストラクタはコンパイラが作っているわけではありません。CLRに関する限り、値型はコンストラクタを持つ必要がありません。 できる ILで書くと と書くと、" new Guid() C# では、通常のコンストラクタを呼び出したときとは異なる IL が出力されます。以下はその例です。 このSOの質問 は、その点についてはもう少し詳しく説明します。

I 容疑者 フレームワークには、パラメータレスコンストラクタを持つ値型がないのです。NDepend にうまく頼めば教えてくれるに違いないのですが・・・。C# がそれを禁止しているという事実は、それがおそらく悪い考えであると考えるのに十分な大きなヒントです。